WKWebView 使用 NSURLProtocol 攔截后的 POST 請(qǐng)求異常及解決方法

原因

首先 WebKit 進(jìn)程是獨(dú)立于 app 進(jìn)程之外的,兩個(gè)進(jìn)程之間使用消息隊(duì)列的方式進(jìn)行進(jìn)程間通信竣贪。比如 app 想使用 WKWebView 加載一個(gè)請(qǐng)求,就要把請(qǐng)求的參數(shù)打包成一個(gè) Message,然后通過(guò) IPC 把 Message 交給 WebKit 去加載玛瘸,反過(guò)來(lái) WebKit 的請(qǐng)求想傳到 app 進(jìn)程的話(比如 URLProtocol ),也要打包成 Message 走 IPC苟蹈。出于性能的原因糊渊,打包的時(shí)候 HTTPBody 和 HTTPBodyStream 這兩個(gè)字段被丟棄掉了,這個(gè)可以參考 WebKit 的源碼慧脱,這就導(dǎo)致 -[WKWebView loadRequest:] 傳出的 HTTPBody 和 NSURLProtocol 傳回的 HTTPBody 全都被丟棄掉了渺绒。所以如果通過(guò) NSURLProtocol 注冊(cè)攔截 http scheme,那么由 WebKit 發(fā)起的所有 http POST 請(qǐng)求就全都無(wú)效了菱鸥,這個(gè)從原理上就是無(wú)解的宗兼。同時(shí)攔截后對(duì) ATS 支持不好。

驗(yàn)證過(guò)程

通過(guò)注冊(cè)NSURLProtocol并注冊(cè)私有API后進(jìn)行NSURLRequest攔截氮采,可以獲取 H5 發(fā)送的請(qǐng)求頭殷绍,但無(wú)法獲取 H5 端的請(qǐng)求。
1.WKWebView 攔截如圖:


WKWebView 攔截

2.UIWebView 攔截如圖:


UIWebView 攔截

解決方案

  1. 修改Scheme
    將 H5 的資源文件與 POST 請(qǐng)求的鏈接使用不同的 Scheme 鹊漠,移動(dòng)端只攔截資源文件的 Scheme 主到,不攔截 POST 地址茶行。
    攔截方式:iOS 11 以上可使用 WKURLSchemeHandler 進(jìn)行攔截,且只允許攔截自定義 Scheme 的請(qǐng)求登钥,不允許攔截“http”畔师、“https”、“ftp”怔鳖、“file”等請(qǐng)求茉唉,否則會(huì) crash。在 iOS 11 以下只能使用私有API:WKBrowsingContextController 和 registerSchemeForCustomProtocol 结执,通過(guò)反射的方式拿到了私有的 class/selector度陆。

  2. POST 請(qǐng)求改為與原生交互
    2.1 將 H5 對(duì) POST 的交互改為與 Native 的橋接,由 Native 負(fù)責(zé)請(qǐng)求接口數(shù)據(jù)献幔,再將數(shù)據(jù)返回給 JS懂傀。
    2.2 注入一段 HookAjax 的 JS 代碼,攔截所有的 XMLHttpRequest 的 POST 請(qǐng)求轉(zhuǎn)移給移動(dòng)端處理蜡感。將 POST 請(qǐng)求通過(guò) JS 和 Native 交互的方式將請(qǐng)求轉(zhuǎn)交給 Native 處理并且在 Native 處理完后將結(jié)果返回給 JS蹬蚁。

小結(jié):
方案1,移動(dòng)端修改小郑兴,前端需要對(duì)數(shù)據(jù)所在的站點(diǎn)重新部署犀斋;
方案2.1,移動(dòng)端情连、前端修改均較大叽粹;
方案2.2,移動(dòng)端較大却舀、前端修改較小虫几,但需要有人幫忙寫 HookAjax 的 JS 代碼。

解決方法

上述的方案1挽拔、2.1對(duì)于前端改動(dòng)較大辆脸,為了避免牽扯過(guò)多人員導(dǎo)致項(xiàng)目進(jìn)展緩慢,則本文采用方案2.2螃诅。
1.注冊(cè)與注銷攔截

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    Class cls = NSClassFromString(@"IMYWebURLProtocol");
    [NSURLProtocol registerClass:cls];
}
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    Class cls = NSClassFromString(@"IMYWebURLProtocol");
    [NSURLProtocol unregisterClass:cls];
}

2.設(shè)置與卸載WKWebViewConfiguration的hookAjax

WKUserContentController *wkUController = [[WKUserContentController alloc] init];
WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
wkWebConfig.userContentController = wkUController;
[wkWebConfig.userContentController imy_installHookAjax]; // hookAjax
//卸載hookAjax
[wkConfig.userContentController imy_uninstallHookAjax];

至此啡氢,hookAjax已經(jīng)結(jié)束,H5的post在被我們攔截后也能正常請(qǐng)求到數(shù)據(jù)了术裸。代碼中涉及到的部分代碼來(lái)源于IMYWebLoader空执。不過(guò)經(jīng)測(cè)試,如果H5加入eruda框架那么會(huì)導(dǎo)致沖突穗椅。于是筆者經(jīng)過(guò)修改后編寫了一份新的js文件:github:WKHookAjax里的ajaxhook.js


2020.03.23更新
對(duì)Get請(qǐng)求方式也進(jìn)行了Hook,因?yàn)閕OS9下的Get方式請(qǐng)求體也為空奶栖。


參考資料
iOS - NSProtocol 攔截 WKWebView POST 請(qǐng)求 body 會(huì)被清空的問(wèn)題解決
Web的一系列優(yōu)化方案
Ajax-hook 原理解析
WKWebView 那些坑
iOS app秒開H5優(yōu)化探索

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匹表,一起剝皮案震驚了整個(gè)濱河市门坷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌袍镀,老刑警劉巖默蚌,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異苇羡,居然都是意外死亡绸吸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門设江,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锦茁,“玉大人,你說(shuō)我怎么就攤上這事叉存÷肓” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵歼捏,是天一觀的道長(zhǎng)稿存。 經(jīng)常有香客問(wèn)我,道長(zhǎng)瞳秽,這世上最難降的妖魔是什么瓣履? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮练俐,結(jié)果婚禮上袖迎,老公的妹妹穿的比我還像新娘。我一直安慰自己痰洒,他們只是感情好瓢棒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丘喻,像睡著了一般脯宿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泉粉,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天连霉,我揣著相機(jī)與錄音,去河邊找鬼嗡靡。 笑死跺撼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的讨彼。 我是一名探鬼主播歉井,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哈误!你這毒婦竟也來(lái)了哩至?” 一聲冷哼從身側(cè)響起躏嚎,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎菩貌,沒想到半個(gè)月后卢佣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡箭阶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年虚茶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仇参。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嘹叫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冈敛,到底是詐尸還是另有隱情待笑,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布抓谴,位于F島的核電站暮蹂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏癌压。R本人自食惡果不足惜仰泻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滩届。 院中可真熱鬧集侯,春花似錦、人聲如沸帜消。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泡挺。三九已至辈讶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間娄猫,已是汗流浹背贱除。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留媳溺,地道東北人月幌。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像悬蔽,于是被迫代替她去往敵國(guó)和親扯躺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件,用以替代 UIKit 中笨...
    Aiana閱讀 4,585評(píng)論 1 8
  • 1录语、WKWebView 白屏問(wèn)題WKWebView 自詡擁有更快的加載速度轴术,更低的內(nèi)存占用,但實(shí)際上 WKWebV...
    無(wú)名感恩閱讀 2,135評(píng)論 0 3
  • 1钦无、WKWebView 白屏問(wèn)題WKWebView 自詡擁有更快的加載速度,更低的內(nèi)存占用盖袭,但實(shí)際上 WKWebV...
    iosRn閱讀 2,098評(píng)論 1 10
  • 導(dǎo)語(yǔ) WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件失暂,用以替代 UIKit...
    Jecky丶閱讀 8,450評(píng)論 2 22
  • 你深邃眼眸 是一望無(wú)際的大海 我終其一生 是張望你的天空
    妃卿閱讀 237評(píng)論 0 4