Can't set headers on my WKWebView POST request
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()
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:
- 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:
andconnectionDidFinishLoading:
from the delegate if you don't use a self signed SSL certificate) - 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]; }}
This appears to be a bug.
https://bugs.webkit.org/show_bug.cgi?id=140188
Hopefully it will be addressed soon. In the meantime, reverting to UIWebView or implementing the workaround proposed by Spas Bilyarski in his answer seems to be the best options.