当使用代码302重定向时,WKWebView无法设置cookie

时间:2017-06-15 20:27:08

标签: ios wkwebview

我向url1发送了请求。 url1将使用cookie重定向到url2。 url2用于授权。我得到代码“302 found”,这是正确的。 但是当url2重定向回url1时,cookie丢失了。这导致我的请求保持重定向到url2,循环直到失败。

有没有人遇到过这种问题并知道解决方案?提前致谢。

这是一个WKWebView问题。 UIWebView可以正常工作。但不知何故,我需要改为使用WKWebView。

我已尝试过许多解决方案,例如Can I set the cookies to be used by a WKWebView?。这些方法可以处理同一域中的cookie。我的问题是url1和url2有不同的域名。重定向时,cookie丢失,导致授权失败,导致url1和url2之间的循环。

是否有人遇到此问题并找到了解决方法?提前谢谢。

7 个答案:

答案 0 :(得分:6)

不幸的是,在WKWebView中没有官方支持处理302重定向响应。我也遇到了同样的问题。有一种方法可以解决,但可能会冒一些风险但不优雅。

  1. 覆盖WKWebView.load(_ request: URLRequest)并使用URLSession代替发出请求。
  2. 确保您的URLSession可以自行处理302重定向,这意味着您需要实现func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void)以指定您不希望URLSession自动处理302重定向。
  3. 使用URLSession获得302响应后,附加的Cookie将自动设置为HTTPCookieStorage.shared。然后使用这些Cookie和响应标头字段Location的网址发出新请求由WKWebView本身。
  4. 代码示例是Here。我是WKWebView的子类,并且在大多数情况下也处理cookie,包括你的302重定向案例。如果它适合你,请给我一个明星thx!

    这是一种非常黑客的方式,如果你想在产品中使用它,请小心。

答案 1 :(得分:3)

如果您需要来自' url2'的后续请求要设置Cookie,您可以尝试使用' WKUserScript'在文档开头通过javascript以编程方式设置值,如下所示:

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

但是,如果您需要在初始加载请求中设置cookie,您可以在NSMutableURLRequest上设置它们,如下所示:

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

您可以将上述两种技术结合起来,将Cookie值从Native环境传输到WebView环境。

您可以参考此link获取有关Cookie的更多高级信息。

答案 2 :(得分:2)

也许聚会晚了,但是上周我遇到了一个与上述问题非常接近的事情,而且从我的角度我得出结论,由于某些原因,WKWebView无法正确处理302响应上的cookie。

如果您的问题与我面临的问题类似:

您需要通过后续身份验证阶段所需的重定向传递一些cookie

然后,您可以轻松地将WKWebView与我在this gist中提供的WKWebView互换。

并按如下所示使用它:

let myWebView = SAWKWebView(frame: .zero)
...
myWebView.load(aRequest, handleRedirect: true, cookies: [myCookies])

cookies不是必需的,可以为零,具体取决于您的设置。

从WKWebView继承的SAWKWebView类,并且直接使用URLSession及其委托来解决上述问题。

通过这种方式,我可以依靠一种足够安全的方式闯入响应302(又名重定向)并使用HTTPStorageCookie手动处理Cookie,而无需依赖javascript和文档,因为根据我的经验,它并不总是可靠的。

执行所需的重定向后,我将内容呈现为HTML并根据需要继续。

答案 3 :(得分:0)

另一种解决方案对我有用:

采用WKNavigationDelegatewebView.navigationDelegate = self,然后:

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

这是我的简单情况所需的全部,但是我想其他人可能还需要复制存储在navigationAction.request中的其他请求信息,例如navigationAction.request.allHTTPHeaderFields

答案 4 :(得分:0)

我已经尝试了其他答案中提出的解决方案,但最终在我看来更好的解决方案是实现此WKNavigationDelegate的方法:

func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {

    if let url = webView.url {
        webView.load(authenticatedRequest(URLRequest(url: url)))
    }
}

authenticatedRequest()是给定请求的私有函数,它将返回带有标头/ cookies /无论您的服务需要进行身份验证的相同请求。

希望有人认为此解决方案有帮助。

答案 5 :(得分:0)

最近我遇到了同样的问题,并且通过执行此操作解决了这个问题。我确定只有在使用iOS <11的情况下,cookie丢失才会发生。为此,您需要像我最近应用的那样解决一些问题。

1-通过更新的cookie来响应服务器端的响应。无论何时从服务器更改

以这种方式从响应中读取Cookie。

if  let allHttpHeaders = response.allHeaderFields as? [String: String] {
            let cookies = HTTPCookie.cookies(withResponseHeaderFields: allHttpHeaders, for: responseUrl)
            for cookie in cookies {
                if cookie.name == "cookie name" {
                    // compare with old cookie value so it will show your cookie is changed now.
                    if "your_old_cookie_value" != cookie.value {

                            //update cookie in Script and request header
                            // reload your page here again.
                        break
                    }
                }
            }
        }

这是最小的更改,可以解决Cookie丢失的问题,对于iOS> = 11应该不是问题,对于ios 11及更高版本,请使用 httpcookiestore

如果您有任何问题,请告诉我。

答案 6 :(得分:-2)

我认为iOS 11的正确解决方案是使用WKHTTPCookieStore。按照keynote的规定,它专门用于解决此问题。