WKWebView Cookie Issue

概述

WKWebView Cookie Issue主要包括:

Cookie丟失問(wèn)題
Cookie同步延遲問(wèn)題

Cookie丟失問(wèn)題

使用過(guò)WKWebView的都會(huì)遇到請(qǐng)求沒(méi)有帶上登錄態(tài),頁(yè)面訪問(wèn)失敗的情況。在UIWebView中發(fā)起的請(qǐng)求會(huì)自動(dòng)帶上存儲(chǔ)于NSHTTPCookieStorage容器中的Cookie,因此,我們一般都會(huì)將登錄態(tài)存儲(chǔ)于NSHTTPCookieStorage中;而WKWebView發(fā)起的請(qǐng)求不會(huì)自動(dòng)帶上存儲(chǔ)于NSHTTPCookieStorage容器中的Cookie,目前主流的解決方案是:

  1. loadRequest前,在request header中設(shè)置Cookie, 解決首個(gè)請(qǐng)求Cookie帶不上的問(wèn)題;
WKWebView *webView = [WKWebView new];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://y.qq.com"]];
[request setValue:@"skey=MgYzJipDFA" forHTTPHeaderField:@"Cookie"];
[webView loadRequest:request]; 
  1. 通過(guò)document.cookie設(shè)置Cookie解決后續(xù)頁(yè)面Ajax、iframe等請(qǐng)求的Cookie問(wèn)題;
WKUserContentController *userContentController = [WKUserContentController new];
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource: @"document.cookie = 'skey=MgYzJipDFA';" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript];

這種方案在遇到302請(qǐng)求的時(shí)候有點(diǎn)捉襟見襯,比如:


第一個(gè)請(qǐng)求RequestA: www.a.com,我們通過(guò)在request header里帶上Cookie:skey=MgYzJipDFA解決該請(qǐng)求的Cookie問(wèn)題,接著RequestA重定向到RequestB:www.b.com,這個(gè)時(shí)候RequestB就可能因?yàn)闆](méi)有攜帶www.b.com域名的Cookie而失敗。更棘手的是這里RequestB:www.b.comRequestA:www.a.com其實(shí)是地址相同的同一個(gè)對(duì)象,也就是說(shuō)RequestB會(huì)帶上我們?cè)赗equestA header里設(shè)置的Cookie:skey=MgYzJipDFA,這樣如果RequestA是重定向到第三方網(wǎng)站,就可能導(dǎo)致Cookie信息泄漏問(wèn)題。當(dāng)然,由于每一次頁(yè)面跳轉(zhuǎn)前都會(huì)調(diào)用回調(diào)函數(shù):

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler; 

可以在該回調(diào)函數(shù)里攔截跳轉(zhuǎn)請(qǐng)求,在request header中帶上或擦除Cookie,確保Cookie字段信息和NSHTTPCookieStorage容器中的一致,并重新loadRequest。不過(guò)這種方法依然解決不了頁(yè)面iframe跨域請(qǐng)求的Cookie問(wèn)題,畢竟-[WKWebView loadRequest:]只適合加載mainFrame Request。

document.cookie不能垮域設(shè)置Cookie,因此,document.cookie添加Cookie的邏輯可以簡(jiǎn)單調(diào)整下:



通過(guò)-[WKUserScript addUserScript:]注入腳本A,A不再是執(zhí)行document.cookie設(shè)置Cookie,而是在documentStart的時(shí)候,拋通知(webkit messageHandlers)給客戶端,客戶端收到通知后,從NSHTTPCookieStorage容器中取出window.location.href對(duì)應(yīng)的Cookie,并執(zhí)行document.cookie將Cookie注入。

Cookie同步問(wèn)題

document.cookie或response set-Cookie設(shè)置的Cookie會(huì)先存儲(chǔ)在WKWebView Cookie緩存(這里WKWebView Cookie緩存的說(shuō)法可能不是很準(zhǔn)確)中,然后再同步到NSHTTPCookieStorage容器中,而同步過(guò)程有1~2s左右的延遲(setCookie有1.5s左右的延遲,而document.cookie的延遲更高些,大概在2.0s左右)。通過(guò)document.cookie設(shè)置Cookie的時(shí)候,如果沒(méi)有指定過(guò)期時(shí)間,則屬于Session Cookie, WKWebView不會(huì)將Session Cookie同步到NSHTTPCookieStorage中,這點(diǎn)和UIWebView有點(diǎn)差異。WKWebView發(fā)起的請(qǐng)求會(huì)自動(dòng)帶上緩存中的Cookie而不會(huì)自動(dòng)帶上NSHTTPCookieStorage中的Cookie。

  1. set-Cookie

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
    

    通過(guò)該回調(diào)函數(shù)可以獲取部分response header set-Cookie字段,將Cookie信息同步到NSHTTPCookieStorage中;

  2. document.cookie
    可以在javascript層hook document.cookie set method,不過(guò)目前發(fā)現(xiàn)只有IOS 10系統(tǒng)上能hook成功;另一種做法是設(shè)置定時(shí)器,檢查document.cookie是否有更新,如果有則拋通知給客戶端,客戶端將Cookie信息同步到NSHTTPCookieStorage中;

  3. WKProcessPool
    通過(guò)讓所有WKWebView共享同一個(gè)WKProcessPool實(shí)例,可以實(shí)現(xiàn)多個(gè)WKWebView之間共享Cookie數(shù)據(jù),尤其是Session Cookie;

相對(duì)完美的方案

前面兩個(gè)問(wèn)題的討論都是建立在WKWebView不支持NSURLProtocol的基礎(chǔ)上,如果WKWbView支持NSURLProtocol:

  1. WKWebView請(qǐng)求將從Network Process轉(zhuǎn)發(fā)到App Process, 最后由Loading System用NSURLConnection發(fā)起請(qǐng)求;
  2. NSURLConnection發(fā)起的請(qǐng)求會(huì)自動(dòng)帶上NSHTTPCookieStorage中的Cookie;
  3. NSURLConnection響應(yīng)的set-Cookie字段會(huì)自動(dòng)存儲(chǔ)到NSHTTPCookieStorage中;

綜合上面3點(diǎn),WKWebView Cookie Issue就只剩下document.cookie的同步問(wèn)題;

筆者對(duì)webkit2沒(méi)有特別深入的了解,如有表述錯(cuò)誤歡迎指正!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容