it-roy-ru.com

Не могу установить заголовки на моем WKWebView POST запрос

Я хочу сделать POST запрос к моей WKWebView, но заголовки не устанавливаются, когда я отслеживаю запросы с Чарльзом, поэтому запрос не выполняется. Что здесь не так?

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-Length это 0, Accept не application/json и тело запроса не было отправлено.

Спасибо за любую помощь.

17
Mattias Eriksson

У меня была та же проблема с WKWebView, которую я решил использовать вместо UIWebView, чтобы избежать сбоя средств выбора в iOS 8. Есть два способа, о которых я могу думать:

  1. Используйте NSURLConnection, чтобы сделать запрос, а затем заполните WKWebView его данными ответа. Вы можете найти пример здесь: https://stackoverflow.com/a/10077796/4116680 (вам нужны только connection:didReceiveData: и connectionDidFinishLoading: от делегата, если вы не используете самозаверяющий SSL-сертификат)
  2. Используйте JavaScript, чтобы сделать запрос POST. Вот пример:

Создать файл, например. "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];
    }
}
14
Spas Bilyarski

Как указывалось в OP, я также подтвердил в Charles, что после webView.load(request) тело составляет 0 байтов.

Есть обходной путь для этой ошибки WKWebView, мы будем инициировать запрос POST, используя URLSession, чтобы преобразовать данные, возвращаемые сервером, в String, и вместо загрузки URL-адреса мы будем использовать loadHTMLString , который будет:

Установите содержимое веб-страницы и базовый URL.

и содержимое является нашей преобразованной строкой:

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

Это похоже на ошибку.
https://bugs.webkit.org/show_bug.cgi?id=140188

Надеюсь, это будет решено в ближайшее время. Между тем, возвращение к UIWebView или реализация обходного пути, предложенного Спасом Билярским в его ответе, кажется наилучшими вариантами.

8
Paul Roe

Я использую этот метод делегата, и он работает !!!

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

Я могу подтвердить эту проблему . Простым обходным решением для меня был запрос AJAX с jQuery:

$.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>

Надеюсь, это кому-нибудь поможет ...

2
Olli D-Metz

обходной путь: обман с использованием html5 & javascript.

Добавьте 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>

Загрузите файл 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]];

Подготовьте параметры к публикации. то есть. строка и массив словаря Примечание: если превратить массив в строку json с помощью NSJSONSerialization, '\ r' может быть добавлено автоматически. Вы должны удалить все '\ r' в строке 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]);
               }
          }];
     }));
 }
1
user7712661

Метод WKWebView.load не работает с пост-запросом с телом поста. Вы должны использовать JavaScript, чтобы сделать трюк, проверьте WKWebView.evaluateJavascript.

Возможно, это ошибка, но Apple до сих пор не обращалась к ней.

0
Xiaodong Ma