2014-10-08 6 views
11

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

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 и не тело запроса не было отправлено.

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

+0

Вы пытались URLEncoding значения электронной почты и пароля перед преобразованием в NSData? –

+0

@StevenVeltema Я пытался отправить 'email = foo & password = bar', но он не работает ни –

+0

Обновлен вопрос !! Понял, что это был WKWebView, который я использовал, он отлично работает в UIWebView. –

ответ

11

У меня был такая же проблема с WKWebView, что я решил использовать вместо UIWebView, чтобы избежать аварий сборщиков в прошивке 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]; 
    } 
} 
+0

спасибо, похоже, действительно приятное решение. но это ошибка в wkwebview, вы думаете, что они решат? Еще раз спасибо, попробуем это! –

+0

Hi @Spas Это то же самое, что я использую, и он отлично работает для каждого приложения, которое я пытаюсь выполнить. , но для facebook, я думаю, что facebook все еще не будет referrer, чтобы быть только m.facebook.com as facebook возвращает мне «не вводите свой пароль на сайте, не находящемся на facebook.com» Я действительно застрял с ним, как при отправке формы , не могу установить заголовок, я попробовал редактирование запроса на 'solvePolicyForNavigationAction', но поскольку он не изменен, он не работает таким образом. Я буду более счастливым. Если у вас есть способ разрешить его – user5821368

+0

, если кто-нибудь знает об этом Issue, plz plz plz ответ – user5821368

4

Это приложение уши, чтобы быть ошибкой.
https://bugs.webkit.org/show_bug.cgi?id=140188

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

+1

ошибка была исправлена ​​месяц назад https://bugs.webkit.org/show_bug.cgi?id=167131 – chebur

+0

@chebur Знаете ли вы номер версии iOS, который впервые принял это исправление? – algrid

1

Я могу подтвердить эту проблему. Простое решение для меня был запрос 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> 

Я надеюсь, что это поможет кому-то ...

4

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

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

Это бесконечно в iOS 10.3 для httpBody. – Max

0

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

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

0

обходной способ: трюк используя 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]); 
       } 
      }]; 
    })); 
} 
4

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

Там обходной путь для этого 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() 
-1

Swift3

Изменение baseurl и token к вашим потребностям.

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

 Смежные вопросы

  • Нет связанных вопросов^_^