场景:
最近有个需求是对UIWebView、WKWebView的https请求进行拦截,然后执行socket + 自定义ssl进行处理
方案:
方案一:自定义NSURLProtocol,配置UIWebView、WKWebView的schemehandler
- 自定义NSURLProtocol,可以拦截UIWebView请求
-
WKWebview进行拦截分为iOS11之前和之后,之前需要调用私有API,之后有专门暴露的方法
’’’ // iOS 11之后 // handler为实现WKURLSchemeHandler接口 [config setURLSchemeHandler:handler forURLScheme:@”https”]; // iOS 11之前 Class cls = [[[WKWebView new] valueForKey:@”browsingContextController”] class]; SEL sel = NSSelectorFromString(@”registerSchemeForCustomProtocol:”); if ([(id)cls respondsToSelector:sel]) { [(id)cls performSelector:sel withObject:@”https”]; } ‘’’
iOS11之后拦截到的请求会走handler中进行处理,要注意对请求cookie的补充。 iOS11之前拦截到的请求会走NSURLProtocol进行处理。
-
由于iOS11之前WKWebView拦截到请求后,会出现body丢失情况。网上的方案是对XMLHTTPRequest进行拦截,转为JS回调原生方式(参考三),测试发现适用于ajax处理;如果是form的提交依旧不能拦截,尝试出的可行方法是,拦截HTMLFormElement的submit方法,由于早期safari支持的js语法版本问题,测试发现只能通过下面方式对form的submit进行拦截,后续处理:转为ajax、参数、header的处理,还需要补充
’’’ function gm_registerForm() { var forms = document.getElementsByTagName(‘form’); for (var index = 0; index < forms.length; index ++) { (function (form_index) { var form = forms[form_index]; form.addEventListener(‘submit’, function (e) { var url = form.getAttribute(‘action’); var method = form.getAttribute(‘method’); var formData = new FormData(form); e.preventDefault(); }, false); })(index); } }
gm_registerForm(); ‘’’
方案二:通过HTTP Proxy
此方案废弃 http proxy有两种方式:1.中间人代理,此方式需要对APP请求时证书做处理,且存在请求的解析后再去发送请求,时间长浪费 2.隧道的方式,但是这种方式于业务不符,业务要进行数据的ssl层加密,此种方式依旧是https默认的ssl层处理方式
参考链接:
参考一: WKWebView 请求拦截探索与实践
参考二: 史上最全的WKWebView问题优化指南
参考三: iOS - NSProtocol 拦截 WKWebView POST 请求 body 会被清空的问题解决
参考四: HTTP 代理原理及实现