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

时间:2014-10-08 09:09:47

标签: ios objective-c nsurlrequest charles-proxy wkwebview

我想向我的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,且未发送请求正文。

感谢您的帮助。

8 个答案:

答案 0 :(得分:14)

我遇到了与WKWebView相同的问题,我决定使用UIWebView来避免iOS 8中的选择器崩溃。我可以想到两种方式:

  1. 使用NSURLConnection发出请求,然后用它的响应数据填充WKWebView。你可以在这里找到一个例子: https://stackoverflow.com/a/10077796/4116680(如果您不使用自签名SSL证书,则只需要代理人connection:didReceiveData:connectionDidFinishLoading:
  2. 使用JavaScript发出POST请求。这是一个例子:
  3. 创建文件,例如。 “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];
        }
    }
    

答案 1 :(得分:14)

正如OP所述,我在Charles中也确认身体在webView.load(request)之后是0字节。

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

  

设置网页内容和基本网址。

,内容是我们转换后的字符串:

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()

答案 2 :(得分:8)

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

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

答案 3 :(得分:7)

我使用此委托方法,它可以工作!!!

cross_validation

答案 4 :(得分:2)

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

我希望这有助于某人...

答案 5 :(得分:1)

解决方法:使用html5&amp;的JavaScript。

将包含以下内容的html5文件添加到您的xcode项目中。使用javascript&amp;发布数据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]];

准备要发布的参数。即。一串&amp;一个字典数组 注意:使用NSJSONSerialization将数组转换为json字符串时,&#39; \ r&#39;可以自动添加。您必须删除所有&#39; \ r&#39;在json字符串中,或​​者无法正确解析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);

将其放入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]);
               }
          }];
     }));
 }

答案 6 :(得分:0)

WKWebView.load方法不适用于帖子正文的帖子请求。您必须使用JavaScript来执行此操作,请检查WKWebView.evaluateJavascript

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

答案 7 :(得分:-2)

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