WKWebview 注入 cookie header 导致重定向循环

WKWebview injecting cookie header cause redirect loop

我正在尝试将我单独获取的 session cookie 注入到 WKWebview 请求中,结果证明这很痛苦...

我设法使用 this solution 注入 session cookie,如下所示:

// Acquiring the cookies
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headers, for: s.request!.url!)

//Appending all the cookies into one raw string.
var cookiesRawString = ""
for c in cookies {
   cookiesRawString += "\(c.name)=\(c.value); "
}

var req: URLRequest = try! URLRequest(url: URL, method: method)

// Then the injection itself
request.setValue(cookiesRawString, forHTTPHeaderField: "Cookie")

webView.load(req)

让我用伪代码快速解释一下服务器逻辑:

  1. 服务器收到对端点 /端点 1 的调用,并附加了初始 session cookies
  2. 然后继续将客户端重定向到 /endpoint2,并在 url.
  3. 中附加用户生成的令牌
  4. 请求附加令牌的第二个端点导致最终重定向到 /endpoint3,Set-Cookie header 包含一次 session cookie
  5. /endpoint3 附加一次 session cookie 导致 200 响应,用户被识别。

问题是,由于某种原因,当我使用上述方法将 cookie 附加到初始请求时,会导致重定向循环,而在 Android 平台上它可以完美运行(我在那里使用类似的注入方法)。

我看到它们之间的唯一区别是 android 应用程序仅在初始请求时 注入 cookies ,而所有后续的重定向调用都没有这些session 饼干。 虽然 ios 在所有重定向调用 上重复初始 session cookie(甚至忽略服务器 set-cookie header 并附加初始session 饼干..).

我是不是做错了什么?如何让 wkwebview 仅在初始请求时使用注入的 cookie?

编辑 1:也尝试回退到 UIWebview,但它产生相同的结果,似乎将 cookie 作为 header 注入并不好,但我尝试使用 HTTPCookieStorage,但它不会保存 cookies!

// the count is 7
var cookiesCount = HTTPCookieStorage.shared.cookies(for: s.request!.url!)?.count

let cookies = HTTPCookie.cookies(withResponseHeaderFields: headers, for: s.request!.url!)

for c in cookies {
   HTTPCookieStorage.shared.setCookie(c)
}

// Count is still 7!            
cookiesCount = HTTPCookieStorage.shared.cookies(for: s.request!.url!)?.count

编辑 2: 好吧,我发现 UIWebview 正在使用 cookie 存储的全局实例,与 alamofire 相同(我用它来获取 session cookie),因此无需手动添加 cookie,该站点认出了用户。

但我仍然更喜欢使用 WKWebview,因为 UIWebview 内存泄漏飞速上升(几个网页导航后超过 100 MB!)。

有没有办法在WKWebview中使用全局cookie jar(alamofire使用的)?

我设法让它在 WKWebview 上运行,使用了一个 hackish 解决方案:

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

    let url = navigationAction.request.url!.absoluteString

    if UserAppendix.isLogin && url != previousNavigateUrl {
        previousNavigateUrl = url
        if url.contains("/endpoint1") {
            let headerFields = navigationAction.request.allHTTPHeaderFields
            let headerIsPresent = headerFields!.keys.contains("Cookie")

            if headerIsPresent {
                decisionHandler(WKNavigationActionPolicy.allow)
            } else {

                var req = URLRequest(url: navigationAction.request.url!)
                let cookies = NetworkAppendix.httpSessionCookies
                let values = HTTPCookie.requestHeaderFields(with: cookies)
                req.allHTTPHeaderFields = values
                webView.load(req)

                decisionHandler(WKNavigationActionPolicy.cancel)
            }
        }
        else if firstTime {
            firstTime = false

            let req = URLRequest(url: navigationAction.request.url!)
            webView.load(req)

            decisionHandler(WKNavigationActionPolicy.cancel)


        }
        else {
            decisionHandler(.allow)
        }
    }
    else {
        decisionHandler(.allow)
    }
}

我在第一个请求上设置 cookie,在第二个请求上中断流程并创建一个新请求(使用重定向 url),以避免我在第一个请求上设置的会话 cookie,所有后续请求都被相同对待。

我知道它并不完美,但它完成了工作。

我认为这可能无关,但我遇到了类似的问题。

原因是修改后的 cookie 弄乱了我使用 NSURL.sharedSession 的所有后续请求。事实证明,使用 WKWebView 设置的 cookie 正在从 NSURLSession.sharedSession 中清除 headers。我认为 cookie 存储在多个会话之间共享。所以,我最终使用了 EphemeralSession,而不是 sharedSession。