I sent request to url1. url1 will redirect to url2 with cookie. url2 is for authorization. And I get code \"302 found\", which is correct. But when url2 redirect back to ur
Maybe late to the party, but I faced something pretty close to the above question last week and also from my side I concluded that for some reason cookies on 302 response are not handled correctly by WKWebView.
If your problem is similar to the one i'm facing with:
you need to pass some cookies from a redirect required for a subsequent authentication stage
Then you can easily interchange your WKWebView with the one I provided into this gist.
and use it like follow:
let myWebView = SAWKWebView(frame: .zero)
...
myWebView.load(aRequest, handleRedirect: true, cookies: [myCookies])
cookies is not required and can be nil, depending on your setup.
SAWKWebView class inheriting from WKWebView and workaround the above problem by using directly URLSession and its delegate.
This way I could rely into a sufficient and safe way to break into the response 302 (aka redirect) and handle cookies manually with HTTPStorageCookie without relying onto javascript and document since in my experience it doesn't always work reliable.
Once the required redirect is performed I render the content as HTML and continue as needed.
I suppose the proper solution for iOS 11 is to use the WKHTTPCookieStore. It's designed to solve exactly this issue as per this keynote.
Another solution worked for me:
Adopt WKNavigationDelegate
, webView.navigationDelegate = self
, then:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
/// Cancel the navigation action
decisionHandler(.cancel)
/// Navigate yourself
let request = NSMutableURLRequest(url: url)
request.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: Auth.getAuthCookies())
webView.load(request as URLRequest)
}
This was all that was needed for my simple case, but I imagine others may also need to copy the other request info that's stored in navigationAction.request
like the navigationAction.request.allHTTPHeaderFields
I've tried the solutions suggested in the other answers but finally the one that seems to work better in my case was implement this WKNavigationDelegate's method:
func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
if let url = webView.url {
webView.load(authenticatedRequest(URLRequest(url: url)))
}
}
Where authenticatedRequest() is a private function that given a request, it returns the same request with the headers/cookies/whatever your service needs to authenticate.
Hope someone find this solution helpful.
Unfortunately, there is no official support for handling 302 redirect response in WKWebView.I came across the same issue too.There is a way to work around but may take some risks and not elegant.
WKWebView.load(_ request: URLRequest)
and use URLSession to make the request instead.func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void)
to specify that you don't want the URLSession to handle 302 redirect automatically.URLSession
the attached cookie will be set to HTTPCookieStorage.shared
automatically.And then make a new request with those cookies and the url of response header field Location
by WKWebView
itself.The code sample is Here.I subclass WKWebView
and also deal with cookies in the most case including your 302 redirect case.If it works for you, please give me a star thx!
It is a really a hack way and be careful if you want use it in product.
If you need subsequent requests from 'url2' to have their cookies set, you can try using 'WKUserScript
' to set the values programmatically via javascript at document start like so:
WKUserContentController* userContentController = WKUserContentController.new;
WKUserScript * cookieScript = [[WKUserScript alloc]
initWithSource: @"document.cookie = 'TeskCookieKey1=TeskCookieValue1';document.cookie = 'TeskCookieKey2=TeskCookieValue2';"
injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
// again, use stringWithFormat: in the above line to inject your values programmatically
[userContentController addUserScript:cookieScript];
WKWebViewConfiguration* webViewConfig = WKWebViewConfiguration.new;
webViewConfig.userContentController = userContentController;
WKWebView * webView = [[WKWebView alloc] initWithFrame:CGRectMake(/*set your values*/) configuration:webViewConfig];
However, if you require your cookies to be set on the initial load request, you can set them on NSMutableURLRequest like so:
WKWebView * webView = /*initialization stuff*/
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"YOUR URL"]];
[request addValue:@"TestCookieKey1=TestCookieValue1;TestCookieKey2=TestCookieValue2;" forHTTPHeaderField:@"Cookie"];
// use stringWithFormat: in the above line to inject your values programmatically
[webView loadRequest:request];
You can combine above two techniques to transfer cookie values from Native environment to WebView environment.
You can refer to this link for more advanced information on cookies.