WKWebView using URLRequest with POST results in nil body

Hello,


I'm writing an application that uses WKWebView on iOS 11.4.

We initiate the webview by loading a remote URL. Then the user navigates normally, but when we are about to load a certain url (as detected by the delegate method "

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {


we must make a submit to a given url (basically we must authenticate the user with a pair of credentials he has stored in the App beforehand).


we tried this

     var urlRequest = URLRequest(url: URL(string: "https://xxxxxx/login")!)
      urlRequest.httpMethod = "POST"
     let params = [
                            "username":   SessionManager.shared.username!,
                            "password":  SessionManager.shared.password!,
                            "vhost": "standard"
      ]
      let postString = self.getPostString(params: params)
        urlRequest.httpBody = postString.data(using: .utf8)
       webView.load(urlRequest)


...
//helper method to build url form request
func getPostString(params:[String:String]) -> String
    {
        var data = [String]()
        for(key, value) in params
        {
            data.append(key + "=\(value)")
            
        }
        return data.map { String($0) }.joined(separator: "&")
    }


But then we check the same request in the delegate method


func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

            print("BODY", navigationAction.request.httpBody)

and the body is null.

In fact the request fails and we get an error in the WKWebView page.


Is this still the bug as in

https://forums.developer.apple.com/thread/18952


or is it something I'm doing wrong?

Thanks

W

Replies

I just discovered that, at least in iOS 13 beta 4, WKWebView doesn't automatically set the Content-Type header to application/x-www-formurlencoded for POST requests the way UIWebView does. Could that be the issue?

I have the same probleme in our client's application for 3DS2 response handling.


We used to have a UIWebView and inspect the httpbody response from 3DS2 form in order to create a "3DSResponse" object in our app, and then determine the credit card informations and if the validation passed or not.


We received a warning that in the future, our builds will be rejected because of the use of UIWebView. So we have to migrate to a WKWebView.


Problem: in the

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)

the

navigationAction.request.httpBody

is equal to nil, so impossible to retreive the result of the form post and what to do with it.


I saw on a lot of forums that it was a known bug of WKWebView, that it was going to be patched in future releases. But for now we are in a urge that on one hand our apps will be rejected if we use UIWebView, and on the other and we can't miss the implementation of 3DS and 3DS2 in our e-commerce application as we are forced to by european legislation.


Is it something finally planned?

WKWebView doesn't automatically set the Content-Type header to application/x-www-formurlencoded for POST requests .

You can add request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type"). to headers manually then it will work

Hi,

You found any solution to this problem? I got stuck in this problem today. Please help me if you have already found a work around.
Thanks!

Hi,
I just checked content type header is already set to application/x-www-form-urlencoded in my 3DS secure request. So, setting content type field will not make http body available on the request.
Thanks!




I am using old UIWebView and got same problem with iOS 13. iOS 13 not reading httpBody, while older iOS worked just fine!

After your solution to add

request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

problem was fixed


Thank you aravapalli

We found a solution that will not require drastic changes or javascript. Basically you need to make use of WKURLSchemeHandler protocol:


1. Setup webview


let config = WKWebViewConfiguration()
config.setURLSchemeHandler(self, forURLScheme: "my-custom-scheme")
let wkWebView = WKWebView(frame: .zero, configuration: config)


2. Implement WKURLSchemeHandler protocol


func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
  if let url = urlSchemeTask.request.url, url.scheme == "my-custom-scheme" {
  self.handleTermURLCallback(urlSchemeTask.request)
  }
}


By using this you'll find that your request httpBody in the callback is not null and you can continue the same way you used to with UIWebView.


Just set the URL to be my-custom-scheme


You'll also no longer need to cancel requests in the WKNavigationDelegate that match your url. This actually ends up being a nice improvement over UIWebView!


It took a lot of effort to find this but it is working for us and we didn't need to change very much. Hope it helps you guys.