概述
WKWebView Cookie Issue主要包括:
Cookie丟失問題
Cookie同步延遲問題
Cookie丟失問題
使用過WKWebView的都會遇到請求沒有帶上登錄態(tài),頁面訪問失敗的情況。在UIWebView中發(fā)起的請求會自動帶上存儲于NSHTTPCookieStorage容器中的Cookie必指,因此,我們一般都會將登錄態(tài)存儲于NSHTTPCookieStorage中入录;而WKWebView發(fā)起的請求不會自動帶上存儲于NSHTTPCookieStorage容器中的Cookie,目前主流的解決方案是:
- loadRequest前佳镜,在request header中設(shè)置Cookie, 解決首個請求Cookie帶不上的問題僚稿;
WKWebView *webView = [WKWebView new];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://y.qq.com"]];
[request setValue:@"skey=MgYzJipDFA" forHTTPHeaderField:@"Cookie"];
[webView loadRequest:request];
- 通過document.cookie設(shè)置Cookie解決后續(xù)頁面Ajax、iframe等請求的Cookie問題蟀伸;
WKUserContentController *userContentController = [WKUserContentController new];
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource: @"document.cookie = 'skey=MgYzJipDFA';" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript];
這種方案在遇到302請求的時候有點(diǎn)捉襟見襯贫奠,比如:
![](http://km.oa.com/files/photos/pictures/201704/1492101755_4_w855_h151.png)
第一個請求
RequestA: www.a.com
,我們通過在request header里帶上Cookie:skey=MgYzJipDFA
解決該請求的Cookie問題,接著RequestA重定向到RequestB:www.b.com
,這個時候RequestB就可能因?yàn)闆]有攜帶www.b.com域名的Cookie而失敗望蜡。更棘手的是這里RequestB:www.b.com
和RequestA:www.a.com
其實(shí)是地址相同的同一個對象,也就是說RequestB會帶上我們在RequestA header里設(shè)置的Cookie:skey=MgYzJipDFA拷恨,這樣如果RequestA是重定向到第三方網(wǎng)站脖律,就可能導(dǎo)致Cookie信息泄漏問題。當(dāng)然腕侄,由于每一次頁面跳轉(zhuǎn)前都會調(diào)用回調(diào)函數(shù):
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
可以在該回調(diào)函數(shù)里攔截跳轉(zhuǎn)請求小泉,在request header中帶上或擦除Cookie,確保Cookie字段信息和NSHTTPCookieStorage容器中的一致冕杠,并重新loadRequest微姊。不過這種方法依然解決不了頁面iframe跨域請求的Cookie問題,畢竟-[WKWebView loadRequest:]只適合加載mainFrame Request分预。
document.cookie不能垮域設(shè)置Cookie兢交,因此,document.cookie添加Cookie的邏輯可以簡單調(diào)整下:
![](http://km.oa.com/files/photos/pictures/201704/1492135575_52_w744_h120.png)
通過-[WKUserScript addUserScript:]注入腳本A笼痹,A不再是執(zhí)行document.cookie設(shè)置Cookie,而是在documentStart的時候配喳,拋通知(webkit messageHandlers)給客戶端酪穿,客戶端收到通知后,從NSHTTPCookieStorage容器中取出window.location.href對應(yīng)的Cookie晴裹,并執(zhí)行document.cookie將Cookie注入被济。
Cookie同步問題
document.cookie或response set-Cookie設(shè)置的Cookie會先存儲在WKWebView Cookie緩存(這里WKWebView Cookie緩存的說法可能不是很準(zhǔn)確)中,然后再同步到NSHTTPCookieStorage容器中涧团,而同步過程有1~2s左右的延遲(setCookie有1.5s左右的延遲只磷,而document.cookie的延遲更高些,大概在2.0s左右)泌绣。通過document.cookie設(shè)置Cookie的時候钮追,如果沒有指定過期時間,則屬于Session Cookie, WKWebView不會將Session Cookie同步到NSHTTPCookieStorage中赞别,這點(diǎn)和UIWebView有點(diǎn)差異畏陕。WKWebView發(fā)起的請求會自動帶上緩存中的Cookie而不會自動帶上NSHTTPCookieStorage中的Cookie。
![](http://km.oa.com/files/photos/pictures/201704/1492102353_10_w379_h304.png)
-
set-Cookie
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
通過該回調(diào)函數(shù)可以獲取部分response header set-Cookie字段仿滔,將Cookie信息同步到NSHTTPCookieStorage中惠毁;
document.cookie
可以在javascript層hook document.cookie set method,不過目前發(fā)現(xiàn)只有IOS 10系統(tǒng)上能hook成功崎页;另一種做法是設(shè)置定時器鞠绰,檢查document.cookie是否有更新,如果有則拋通知給客戶端飒焦,客戶端將Cookie信息同步到NSHTTPCookieStorage中蜈膨;WKProcessPool
通過讓所有WKWebView共享同一個WKProcessPool實(shí)例,可以實(shí)現(xiàn)多個WKWebView之間共享Cookie數(shù)據(jù)牺荠,尤其是Session Cookie;
相對完美的方案
前面兩個問題的討論都是建立在WKWebView不支持NSURLProtocol的基礎(chǔ)上翁巍,如果WKWbView支持NSURLProtocol:
- WKWebView請求將從Network Process轉(zhuǎn)發(fā)到App Process, 最后由Loading System用NSURLConnection發(fā)起請求;
- NSURLConnection發(fā)起的請求會自動帶上NSHTTPCookieStorage中的Cookie;
- NSURLConnection響應(yīng)的set-Cookie字段會自動存儲到NSHTTPCookieStorage中休雌;
綜合上面3點(diǎn)灶壶,WKWebView Cookie Issue就只剩下document.cookie的同步問題;
筆者對webkit2沒有特別深入的了解杈曲,如有表述錯誤歡迎指正疏虫!