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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26253133/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:04:44  来源:igfitidea点击:

Can't set headers on my WKWebView POST request

iosobjective-cnsurlrequestcharles-proxywkwebview

提问by Mattias Farnemyhr

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

我想向我发送 POST 请求,WKWebView但是当我使用 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];

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-Lengthis 0, Acceptis not application/jsonand no request body were sent.

因此,如您所见,Content-Lengthis 0Acceptis notapplication/json并且没有发送请求正文。

Thanks for any help.

谢谢你的帮助。

采纳答案by Spas Bilyarski

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:

我在使用 WKWebView 时遇到了同样的问题,我决定使用它而不是 UIWebView 来避免 iOS 8 中的选择器崩溃。我可以想到两种方法:

  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:
  1. 使用 NSURLConnection 发出请求,然后用它的响应数据填充 WKWebView。你可以在这里找到一个例子:https: //stackoverflow.com/a/10077796/4116680(如果你不使用自签名的 SSL 证书,你只需要connection:didReceiveData:connectionDidFinishLoading:来自委托)
  2. 使用 JavaScript 发出 POST 请求。下面是一个例子:

Create file eg. "POSTRequestJS.html":

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

最后添加 WKNavigationDelegate:

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

回答by OhadM

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

正如 OP 所说,我还在 Charles 中确认了 .body 之后的 0 个字节webView.load(request)

There's a workaround for this WKWebViewbug, we will initiate a POSTrequest using URLSession convert the data returned by the server to Stringand instead of loading the url we will use loadHTMLStringwhich will:

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

Set the webpage contents and base URL.

设置网页内容和基本 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()

回答by Paul Roe

This appears to be a bug.
https://bugs.webkit.org/show_bug.cgi?id=140188

这似乎是一个错误。
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.

希望它会很快得到解决。与此同时,恢复到 UIWebView 或实施 Spas Bilyarski 在他的回答中提出的解决方法似乎是最好的选择。

回答by Harish Pathak

I use this delegate method and it works !!!

我使用这个委托方法,它有效!!!

#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);
    }
}

回答by olidem

I can confirm this problem. A simple workaround for me was an AJAX request, with jQuery:

我可以确认这个问题。对我来说一个简单的解决方法是使用 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);
});

where my form looks like

我的表格看起来像

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

I hope this helps somebody...

我希望这可以帮助某人...

回答by user7712661

workaround: trick by using html5 & javascript.

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

Add a html5 file with content below to your xcode project. To post data by using javascript & h5 form:

将包含以下内容的 html5 文件添加到您的 xcode 项目。使用 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>

Load the h5 file to WKWebView:

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

Prepare the parameters to post. ie. a string & an array of dictionary Note: when turn array to json string by using NSJSONSerialization, '\r' may be added automaticly. You must remove all the '\r' in the json string, or the javascript cannot be parsed correctly.

准备要发布的参数。IE。一个字符串和一个字典数组 注意:当使用 NSJSONSerialization 将数组转换为 json 字符串时,可能会自动添加 '\r'。您必须删除 json 字符串中的所有 '\r',否则无法正确解析 javascript。

// 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);

Put this in the WKWebView's delegate: didFinishNavigation

把它放在 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]);
               }
          }];
     }));
 }

回答by Xiaodong Ma

WKWebView.loadmethod doesn't work with post request with post body. You have to use JavaScript to do the trick, check WKWebView.evaluateJavascript.

WKWebView.load方法不适用于带有帖子正文的帖子请求。你必须使用 JavaScript 来完成这个技巧,检查WKWebView.evaluateJavascript.

It maybe a bug, but Apple hasn't addressed it till now.

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