Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 584
Mattias Farnemyhr Avatar asked Oct 08 '14 09:10

Mattias Farnemyhr


People also ask

Is WKWebView deprecated?

Since then, we've recommended that you adopt WKWebView instead of UIWebView and WebView — both of which were formally deprecated. New apps containing these frameworks are no longer accepted by the App Store.

How do I refresh WKWebView?

The WKWebView already contains a scrollview. All you need to do is create the refresh control, assign a target function that will get called when a user initiates a refresh, and attach the refresh control to the scrollview.

How can I clear the contents of a UIWebView WKWebView?

To clear old contents of webview With UIWebView you would use UIWebViewDelegate 's - webViewDidFinishLoad: .


2 Answers

As the OP stated, I have also confirmed in Charles that the body is 0 bytes after webView.load(request).

There's a workaround for this WKWebView bug, we will initiate a POST request using URLSession convert the data returned by the server to String and instead of loading the url we will use loadHTMLString which will:

Set the webpage contents and base URL.

and the content is our converted string:

var request = URLRequest(url: URL(string: "http://www.yourWebsite")!) request.httpMethod = "POST" let params = "do=something&andAgain=something" request.httpBody = params.data(using: .utf8)  let task = URLSession.shared.dataTask(with: request) { (data : Data?, response : URLResponse?, error : Error?) in         if data != nil {             if let returnString = String(data: data!, encoding: .utf8) {                 self.webView.loadHTMLString(returnString, baseURL: URL(string: "http://www.yourWebsite.com")!)             }         } } task.resume() 
like image 196
OhadM Avatar answered Oct 17 '22 03:10

OhadM


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];     } } 
like image 21
Spas Bilyarski Avatar answered Oct 17 '22 03:10

Spas Bilyarski