简介:mPaas-WKWebview网络拦截常见问题
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技术学院钉钉圈子,和更多云上人交流关于云平台的那些事。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。