lionheart / openradar-mirror

A mirror of radars pulled from http://openradar.me/.
244 stars 17 forks source link

20464240: It's not possible to perform a POST request with HTTPBody content in a WKWebView. #1558

Open openradar-mirror opened 9 years ago

openradar-mirror commented 9 years ago

Description

Summary: WKWebView will empty the HTTPBody of a POST URLRequest. Creating a URLRequest with a HTTPBody and using this request to load content in the WKWebView. Will result in the WKWebView emptying the HTTPBody.

Steps to Reproduce:

Or use this code snippet:

Expected Results: The request going out to the www.apple.com server will not contain the HTTPBody. This works in UIWebView.

Actual Results: HTTPBody is nil.

Version: iOS 8.2 (12D508)

Notes:

Configuration: iPad air, iPhone 6, iOS simulators

Product Version: iOS 8.2 Created: 2015-04-08T10:56:00.719581 Originated: 2015-04-07T12:49:00 Open Radar Link: http://www.openradar.me/20464240

tsheaff commented 8 years ago

Any update on a workaround to this. I'd like to migrate to WKWebView for memory reasons, but this seems to be a dealbreaker (I'm using a POST with body to fetch some of my content from my web server)

enagorny commented 8 years ago

This is WebKit bug https://bugs.webkit.org/show_bug.cgi?id=140188

On SO there is workaround http://stackoverflow.com/a/26342224/720544 Personally I opted to old UIWebView.

tommeier commented 7 years ago

Still an issue.

Dealbreaker for us too. When using a Rails backend and hitting DELETE routes, the usual Rails hack is for a POST and a hidden input field indicating it is a _method=delete with this bug, no httpBody and the wrong route is triggered.

On UIWebView no issues what so ever. Unable to use the workarounds as the POST is triggered within the WebView and not from app code. I'd also consider it to be too much of a risk for someone to accidentally use a normal POST with body going forward and not notice iOS WKWebView is unable to process the body.

nesterenkodm commented 7 years ago

the bug has been fixed a month ago. I hope it will be soon in production https://bugs.webkit.org/show_bug.cgi?id=167131

qazx84265 commented 7 years ago

workaround: trick by using html5

& javascript.

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

    `

  2. Load the h5 file to 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]];

  3. 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. `// 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);`

  4. put this in the WKWebView's delegate: didFinishNavigation // call the javascript in step 3 GCD_MAIN((^{ [_web evaluateJavaScript:jscript completionHandler:^(id object, NSError * _Nullable error) { if (error) { NSLog(@"----------->>>>>>>>>>>>> evaluateJavaScript error : %@", [error localizedDescription]); } }]; }));

orj commented 7 years ago

This might have been fixed in iOS 11. See:

https://bugs.webkit.org/show_bug.cgi?id=167131

ataranlen commented 7 years ago

@orj Doesn't appear to be fixed. In our app, the issue is visible from a webpage containing an HTML Form that is already loaded in the WKWebView. Submitting the form via a tap would result in an empty httpBody. Tested with the latest version of the iOS 11 SDK in xCode 9, and in the delegate method on WKwebView decidePolicyForNavigationAction, the WKNavigationAction's URLRequest's httpbody is still nil.

In this use case, I was able to work around it using some JQuery.

let urlRequest = navigationAction.request
guard let httpBody = urlRequest.httpBody else {
    var newRequest = urlRequest
    webView.evaluateJavaScript("$('form').serialize()", completionHandler: { (html: Any?, error: Error?) in
        if let query = html as? String {
            newRequest.httpBody = query.data(using: .utf8)
    }

    //Load Request with httpBody here.

    })

    decisionHandler(WKNavigationActionPolicy.cancel)
}

Obviously this code won't work for everyone, as this assumes JQuery is present in the page that is already loaded.

kamvoick commented 6 years ago

This still doesn't work. HttpBody is empty every time. Any workaround for non-jquery script?

arkilis commented 6 years ago

@kamvoick I tried with the above method which is not working. For people who met this problem, using JavaScript is the only option.

ataranlen commented 6 years ago

@kamvoick @arkilis Unfortunately, my JQuery code no longer seems to work consistently for me either across iOS 9-11.3. I'm still using the JQuery hack because it works to rebuild the URLRequest to pass to a separate WKWebView which includes the Javascript workaround.

Still doesn't work for every site. Combining this with the lack of proper handling of cookies received on a 302 redirect (common after a POST), I started looking at SFSafariViewController to handle some of the websites we need to show in our app, as POST requests from within a page seem to work fine. But SFSafariViewController seems to no longer share cookies with the device's Safari. And to make matters worse, an SFSafariViewController won't accept a POST as the initial request either.

So what I'm left with is some crazy shoe-horning of multiple WKWebView's for some requests (one to maintain a session, and one to handle external sites that won't accept cookies from said session) and using SFSafariViewController for others.

huwr commented 6 years ago

Could be this bug we're experiencing: https://bugs.webkit.org/show_bug.cgi?id=140188

musicdev20 commented 5 years ago

Does anyone know of a better workaround for this? This has me dead in the water for my hybrid app where the user can't navigate using form buttons. :( Incredibly frustrating.

lijusparkt commented 4 years ago
  var request = new NSMutableUrlRequest(new NSUrl(new NSString(paymentwebview.url))); //Your Url
            request.HttpMethod = "POST";
            request.Body = NSData.FromString(paymentwebview.data); //Data for POST
            request["Content-Length"] = request.Body.Body.Length.ToString();
            request["Content-Type"] = "application/x-www-form-urlencoded charset=utf-8";
            LoadRequest(request);