无法在我的WKWebView POST请求上设置标题

我想对我的WKWebView执行一个POST请求,但是当我使用Charles来监视这个请求时,这个头部并没有被设置,所以请求失败了。 这里有什么问题?

 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]; 

这就是查尔斯所说的要求是这样的:

 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 

所以,你可以看到, Content-Length0Accept不是application/json ,也没有发送请求体。

谢谢你的帮助。

我与WKWebView有同样的问题,我决定使用而不是UIWebView来避免iOS 8中的select器崩溃。我可以想到两种方法:

  1. 使用NSURLConnection进行请求,然后用它的响应数据填充WKWebView。 你可以在这里find一个例子: https connection:didReceiveData: (你只需要connection:didReceiveData:connectionDidFinishLoading:如果你不使用一个自签名的SSL证书从委托)
  2. 使用JavaScript来发出POST请求。 这里是一个例子:

创build文件,例如。 “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> 

在你想要加载你的请求的地方你的代码中:

 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]]; 

添加方法:

 - (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; } 

最后添加WKNavigationDelegate:

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

这似乎是一个错误。
https://bugs.webkit.org/show_bug.cgi?id=140188

希望这个问题很快就会解决。 与此同时,恢复到UIWebView或实施温泉Bilyarski在他的答案中提出的解决方法似乎是最好的select。

我使用这个委托方法,它的工作原理!

 #pragma mark - WKNavigationDelegate - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ NSLog(@"%@",navigationAction.request.allHTTPHeaderFields); NSString *accessToken = @"Bearer 527d3401f16a8a7955aeae62299dbfbd"; NSMutableURLRequest *request = [navigationAction.request mutableCopy]; if(![[request.allHTTPHeaderFields allKeys] containsObject:@"Authorization"]){ [request setValue:accessToken forHTTPHeaderField:@"Authorization"]; decisionHandler(WKNavigationActionPolicyCancel); [Helper hideProgressHUD]; [webView loadRequest:request]; } else { decisionHandler(WKNavigationActionPolicyAllow); } } 

正如OP所说,我也已经在Charles中确认,body是webView.load(request)之后的0个字节。

有一个这个WKWebView错误的解决方法,我们将启动一个使用URLSession的POST请求将服务器返回的数据转换为String ,而不是加载URL,我们将使用loadHTMLString这将:

设置网页内容和基本url。

内容是我们转换的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() 

我可以证实这个问题。 对我来说简单的解决方法是使用jQuery的AJAX请求:

 $.ajax({ type : 'POST', url : $('#checkout-form').attr('action'), data : $('#checkout-form').serialize() }).done(function(response, status) { // response if return value 200 }).fail(function(status, error) { console.log(error); }); 

我的表单看起来像

 <form id="checkout-form" method="POST" action="/shop/checkout"> ... </form> 

我希望这可以帮助别人…

WKWebView.load方法不适用于post正文的发布请求。 你必须使用JavaScript来做伎俩,检查WKWebView.evaluateJavascript

这可能是一个错误,但苹果直到现在还没有解决。

解决方法:通过使用html5&javascript技巧。

将下面的内容添加到您的xcode项目中的html5文件。 使用javascript&h5表单发布数据:

 <html> <head> <script> //how to call: 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> 

将h5文件加载到WKWebView:

 WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init]; config.preferences = [[WKPreferences alloc]init]; config.preferences.javaScriptEnabled = YES; WKWebView* webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:config]; webView.navigationDelegate = self; [self.view addSubview:webView]; NSString *path = [[NSBundle mainBundle] pathForResource:@"JSPOST" ofType:@"html"]; NSString *html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; [webView loadHTMLString:html baseURL:[[NSBundle mainBundle] bundleURL]]; 

准备参数发布。 即。 一个string&字典数组注意:当使用NSJSONSerialization将数组转换为jsonstring时,可以自动添加'\ r'。 您必须删除jsonstring中的所有'\ r',否则javascript无法正确parsing。

 // parameters to post NSString* name = @"Swift"; NSArray* array = @[@{@"id":@"1", @"age":@"12"}, @{@"id":@"2", @"age":@"22"}]; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:array options:NSJSONWritingPrettyPrinted error:nil]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\'"]; // trim spaces and newline characters jsonString = [jsonString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\r" withString:@""]; jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\n" withString:@""]; NSString *postData = [NSString stringWithFormat: @"'name':'%@', 'contacts':'%@'", name, jsonString]; // page url to request NSString *urlStr = @"http:api.example.com/v1/detail"; // javascript to evalute NSString *jscript = [NSString stringWithFormat:@"post('%@',{%@});", urlStr, postData]; //NSLog(@"Javzascript: %@", jscript); 

把这个放在WKWebView的委托中: didFinishNavigation

 // call the javascript in step 3 (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { GCD_MAIN((^{ [_web evaluateJavaScript:jscript completionHandler:^(id object, NSError * _Nullable error) { if (error) { NSLog(@"----------->>>>>>>>>>>>> evaluateJavaScript error : %@", [error localizedDescription]); } }]; })); } 

Swift3

根据需要更改baseurltoken

 extension MyWebView: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) { let request: URLRequest = navigationAction.request let urlString: String = request.url?.absoluteString ?? "" let baseurl: String = "http://materik.me/" let needsAuthorization: Bool = urlString.hasPrefix(baseurl) if !needsAuthorization { print("url doesn't need authorization. \(urlString)") decisionHandler(.allow) return } let headerFields: [String : String] = request.allHTTPHeaderFields ?? [:] //print("url: \(urlString) fields: \(headerFields)") if headerFields["Authorization"] != nil { print("already has authorization header. \(urlString)") decisionHandler(.allow) return } print("add authorization header. \(urlString)") let token: String = "sw_gu6GpGXRG50PR9oxewI" var mutableRequest = request mutableRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") decisionHandler(.cancel) webView.load(mutableRequest) } }