1. 背景
原生WKWebView在獨立於app進程之外的進程中執行網絡請求,請求數據不經過主進程,因此在 WKWebView 上直接使用NSURLProtocol 是無法攔截請求的。但是由於mPaas的離線包機制強依賴網絡攔截,所以基於此,mPaas利用了WKWebview的隱藏api,去註冊攔截網絡請求去滿足離線包的業務場景需求,參考代碼如下:
[WKBrowsingContextController registerSchemeForCustomProtocol:@"https"]
但是因為出於性能的原因,WK的網絡請求在給主進程傳遞數據的時候會把請求的body去掉,導致攔截後請求的body參數丟失。在離線包場景,由於頁面的資源不需要body數據,所以離線包可以正常使用不受影響。但是在H5頁面內的其他post請求會丟失data參數。為了解決post參數丟失的問題,mPaas通過在js注入代碼,hook了js上下文裡的XMLHTTPRequest對象解決。通過在JS層把方法內容組裝好,然後通過WKWebView的messageHandler機制把內容傳到主進程,把對應HTTPBody然後存起來,隨後通知JS端繼續這個請求,網絡請求到主進程後,在將post請求對應的HttpBody添加上,這樣就完成了一次post請求的處理。整體流程可以參考之前崔同學的分享流程圖如下:
圖1
2. 遇到的問題
通過上面的機制,既滿足了離線包的資源攔截訴求,也解決了post請求body丟失的問題。但是在一些場景還是存在一些問題,需要開發者進行適配。
2.1. mPaas容器和三方容器混用導致三方容器請求body丟失
2.1.1. 問題場景
典型的場景,是在App內同時集成了多個wkwebview容器,常見的問題現象如下:打開mPaas容器後在打開三方的WK頁面,三方WK頁面內的post請求body參數丟失。原因是因為mPaas容器註冊了全局的網絡攔截,導致三方容器內的請求,也走到了mPaas的網絡攔截,但是因為mPaas容器沒有啟動,所以無法正常走到mPaas全局攔截補全body的鏈路,導致body參數丟失。
2.1.2. 解決方案
在三方容器創建的時候反註冊,在銷燬的時候再註冊回來。
j//反註冊
Class cls = NSClassFromString(@"WKBrowsingContextController");
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"unregisterSchemeForCustomProtocol:"]);
if ([(id)cls respondsToSelector:sel]) {
[(id)cls performSelector:sel withObject:@"http"];
[(id)cls performSelector:sel withObject:@"https"];
}
//註冊
Class cls = NSClassFromString(@"WKBrowsingContextController");
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"registerSchemeForCustomProtocol:"]);
if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel withObject:@"http"];
[(id)cls performSelector:sel withObject:@"https"];
#pragma
}
2.2. mPaas容器打開離線包後直接訪問虛擬域名導致白屏
2.2.1. 問題場景
和上面第一個case類似,也是在App內同時集成了多個wkwebview容器,同時三方的容器也會操作全局的網絡攔截,導致mPaas的網絡攔截失效。常見的問題現象如下:打開三方容器後,在打開mPaas的離線包後,發現離線包會直接通過在線網絡訪問虛擬域名,不走離線,導致頁面白屏。
2.2.1. 解決方案
參考第一個問題的解決方案,在啟動mPaas容器的時候,確認全局的網絡攔截是可以正常生效的就可以。
2.3. mPaas容器內sendBeacn請求body丟失
2.3.1. 問題場景
有客戶在容器內集成了神策的埋點jssdk,發現埋點請求裡的body參數丟失。通過查看源碼發現神策jssdk是通過navigator.sendBeacon發送的請求,目前mPaas內hook的js請求,只支持XMLHTTPRequest,sendBeacon還不支持,所以導致走了網絡攔截後body參數丟失。
圖2
2.3.1. 解決方案
神策sdk內支持指定ajax的方式上報埋點,修改上報方式為ajax後問題解決。可參考文後資料[1]瞭解詳情。
圖3
[1]JavaScript SDK 使用說明:https://www.sensorsdata.cn/2.0/manual/js_sdk.html
我們是阿里雲智能全球技術服務-SRE團隊,我們致力成為一個以技術為基礎、面向服務、保障業務系統高可用的工程師團隊;提供專業、體系化的SRE服務,幫助廣大客戶更好地使用雲、基於雲構建更加穩定可靠的業務系統,提升業務穩定性。我們期望能夠分享更多幫助企業客戶上雲、用好雲,讓客戶雲上業務運行更加穩定可靠的技術,您可用釘釘掃描下方二維碼,加入阿里雲SRE技術學院釘釘圈子,和更多雲上人交流關於雲平臺的那些事。