web-dev-qa-db-fra.com

Impossible de définir les en-têtes sur mon WKWebView POST demande

Je souhaite faire une demande POST à ma WKWebView, mais les en-têtes ne sont pas configurés lorsque je surveille les demandes avec Charles et que la demande échoue. Qu'est-ce qui ne va pas ici?

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

Et voici ce que Charles dit que la demande est comme:

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

Ainsi, comme vous pouvez le constater, Content-Length est 0, Accept n’est pas application/json et aucun corps de requête n’a été envoyé.

Merci pour toute aide.

17
Mattias Eriksson

Comme l'OP l'a indiqué, j'ai également confirmé à Charles que le corps avait 0 octet après webView.load(request).

Il existe une solution de contournement pour ce bogue WKWebView, nous allons initier une requête POST en utilisant URLSession pour convertir les données renvoyées par le serveur en String et au lieu de charger l'URL, nous utiliserons loadHTMLString qui:

Définissez le contenu de la page Web et l'URL de base.

et le contenu est notre chaîne convertie:

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

Cela semble être un bug.
https://bugs.webkit.org/show_bug.cgi?id=140188

Espérons que cela sera bientôt résolu. Entre-temps, revenir à UIWebView ou appliquer la solution de contournement proposée par Spas Bilyarski dans sa réponse semble être la meilleure des options.

8
Paul Roe

J'utilise cette méthode de délégué et ça marche !!!

#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

Je peux confirmer ce problème… .. Une solution de contournement simple pour moi était une requête AJAX, avec 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);
});

où ma forme ressemble

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

J'espère que cela aide quelqu'un ...

2
Olli D-Metz

solution de contournement: astuce en utilisant html5 & javascript.

Ajoutez un fichier html5 avec le contenu ci-dessous à votre projet xcode. Pour publier des données en utilisant le formulaire 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>

Chargez le fichier h5 dans 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]];

Préparez les paramètres à poster. c'est à dire. une chaîne et un tableau de dictionnaire Remarque: lorsque vous réglez tableau en chaîne json à l'aide de NSJSONSerialization, '\ r' peut être ajouté automatiquement. Vous devez supprimer tous les '\ r' de la chaîne json, sinon le javascript ne peut pas être analysé correctement.

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

Mettez ceci dans le délégué de 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

La méthode WKWebView.load ne fonctionne pas avec une demande de publication avec un corps de publication. Vous devez utiliser JavaScript pour faire l'affaire, cochez WKWebView.evaluateJavascript.

C'est peut-être un bug, mais Apple ne l'a pas encore résolu.

0
Xiaodong Ma