Search code examples
iosobjective-cnsurlrequestcharles-proxywkwebview

Can't set headers on my WKWebView POST request


I want to do a POST request to my WKWebView but the headers doesn't get set when I monitor the requests with Charles so the request fails. What is wrong here?

NSString *post = [NSString stringWithFormat: @"email=%@&password=%@", email, password];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *contentLength = [NSString stringWithFormat:@"%d", postData.length];

NSURL *url = [NSURL URLWithString:@"http://materik.me/endpoint"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:postData];
[request setValue:contentLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];

[webview loadRequest:request];

And this is what Charles says the request is like:

POST /endpoint HTTP/1.1
Host: materik.me
Content-Type: application/x-www-form-urlencoded
Origin: null
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (iPhone; CPU OS 8_0 like Mac OS X)
Content-Length: 0
Accept-Language: en-us
Accept-Encoding: gzip, deflate

So, as you can see, Content-Length is 0, Accept is not application/json and no request body were sent.

Thanks for any help.


Solution

  • I had the same problem with WKWebView, that I decided to use instead of UIWebView to avoid the pickers crash in iOS 8. There are two ways that I can think of:

    1. Use NSURLConnection to make the request and then fill the WKWebView with it's response data. You can find an example here: https://stackoverflow.com/a/10077796/4116680 (You only need connection:didReceiveData: and connectionDidFinishLoading: from the delegate if you don't use a self signed SSL certificate)
    2. Use a JavaScript to make the POST request. Here is an example:

    Create file eg. "POSTRequestJS.html":

    <html>
        <head>
            <script>
                //POST request example:
                //post('URL', {key: 'value'});
                function post(path, params) {
                    var method = "post";
                    var form = document.createElement("form");
                    form.setAttribute("method", method);
                    form.setAttribute("action", path);
    
                    for(var key in params) {
                        if(params.hasOwnProperty(key)) {
                            var hiddenField = document.createElement("input");
                            hiddenField.setAttribute("type", "hidden");
                            hiddenField.setAttribute("name", key);
                            hiddenField.setAttribute("value", params[key]);
    
                            form.appendChild(hiddenField);
                        }
                    }
    
                    document.body.appendChild(form);
                    form.submit();
                }
            </script>
        </head>
        <body>
        </body>
    </html>
    

    And in your code after where you want to load your request:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"POSTRequestJS" ofType:@"html"];
    NSString *html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    WKWebView.navigationDelegate = self;
    [WKWebView loadHTMLString:html baseURL:[[NSBundle mainBundle] bundleURL]];
    

    Add method:

    - (void)makePostRequest
    {
        NSString *postData = [NSString stringWithFormat: @"email=%@&password=%@", email, password];
        NSString *urlString = @"http://materik.me/endpoint";
        NSString *jscript = [NSString stringWithFormat:@"post('%@', {%@});", urlString, postData];
    
        DLog(@"Javascript: %@", jscript);
    
        [WKWebView evaluateJavaScript:jscript completionHandler:nil];
    
        didMakePostRequest = YES;
    }
    

    And last add the WKNavigationDelegate:

    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
    {
        if (!didMakePostRequest) {
            [self makePostRequest];
        }
    }