对于一个没有其它领域开发背景的APP开发人员来说,“跨域资源访问”可能真的不属于我们需要认真关心的问题。就原生开发来说,主流的接口开发模式大多数都转变成无状态的接口请求方式,一方面可以真正迎合APP在开发过程中的简单适用性。对于服务端来说,在后期的优化及扩展实现上更简单灵活。无需要像网页开发一样,用临时隐藏cookit字段的方式实现用户身份的辨认(Session)。APP在进行接口请求时,都可以在HTTP头或者body中附带个人身体识别码(token)等信息给到接口进行身份识别。所以,就这么简单粗暴。
但是,尽管这样,我们做这行,多知道点东西还是没坏处的,说不定哪天就用上了。
于是,这么一天就到了。也就是前段时间,我们的专车项目有一部分边缘业务是以混合开发的模式嵌入了WKWebview进行H5页面的展示。对于我们做APP的人来说,这是再简单不过的事情了。
开发好之后给到测试人员进行测试的时候,我们发现很多系统上都没测到H5在WKWebview运行的问题,唯独在IOS12系统的手机上,有些流程不能走通。在排除了各方面问题后,一班人感觉束手无策。
这时候,web前端怀疑是服务端接口的问题,服务端接口在怀疑是我们APP的问题。对于很多APP开发人员来说,WKWebview的使用也就那么回事了,想做错都比较难,于是就陷入僵局。
因为打车项目只是我们团队开发的众多项目中比较小的一个,我就安排了一两个人去做项目的更新迭代,到时下午开小组会议的时候我才得知问题的存在。在初步得知情况后,把问题指向了 “是否WKWebview在IOS12系统上存在宽容度的差异”
的问题进行了思考。
于是我一方面与前端开发人员进行了问题的沟通,询问其web处理流程后,可以初步确定是由于 WKWebview在IOS12系统中,进行复杂跨域处理时,跨域流程无法正常进行
的问题。
因为是web端开发的相关知识,为了更好理解下面的内容,这里我就简单总结带过一下。
说到跨域资源访问
就不得不说跨域资源保护
。
跨域资源保护
是浏览器提供的一种最为基本的安全保护策略,当前域上的脚本想访问其它域上的资源都要在该策略下进行。
当前,web开发采用的前后端分离的开发方式已经是比较普遍的了。在该项目中,H5面页在完成加载后,会以异步请求的方式对页面中的数据进行异步加载及显示。在进行异步请求的时候,调用了另一个项目的接口进行数据加载。协议 + 域名 + 端口
中基中一者与当前资源不一致的时候,就构成了 跨域资源访问
。
解决web端的跨域问题的方案有几个,CORS是业内较为常用的标准,为大多数常用的浏览器所支持。
CORS的实现方式或者处理方式上,可以分为:简单跨域处理
和 *复杂跨域处理
下面就简单带过一下:
我就不一一列出什么才是属于“简单跨域”的条件了,简单来说就是在一般简单的标准HTTP请求过程中,如果浏览器识别到你请求的资源与当前的“域”不一致的时候,会自动在HTTP头添加Origin: www.xxx.com
信息给到服务端接口进行简单跨域请求的处理.
服务端接口在收到你的请求时,对Origin信息进行获取,并进行相关判断后。对该请求表示接受时,在返回的清求中附带Access-Control-Allow-Origin
的参数放到HTTP头中。
浏览器在接收到简单跨域请求返回时,判断Access-Control-Allow-Origin
是否有正确返回 (一般的值可以为 * ,或者返回访问域)。如果没有,将终止流程继续进行。(当然,这里还有其它值的返回,这里就不一一说明了)
复杂跨域的条件我就不一一说了。在我们当前项目中,由于H5在进行跨域异步请求时,在HTTP请求中加入了几个自定义的HTTP头
。
浏览器在侦测到复杂跨域请求时,会先发一个Option
请求到对应的服务端,请求跨域的允许。
服务端在接收到Option
请求时,会与上面的“简单跨域请求”一样,返回几个头信息。
浏览器在接收到Option请求返回的结果进行判断是否继续后续正式请求
的发送。
得出结论:与硬件平台无关,与软件系统有关。问题只出现在IOS12的系统上
通过对H5脚本进行分析,得出跨域类型为:复杂跨域
也可以说是 非简单跨域
通过对整个过程进行抓包处理,得出结论:服务端在进行复杂跨域
的预处理上,初步实现
对相关头信息的返回。但在IOS12系统的WKWebview上,接口接收到Option复杂跨域请求,正常返回后,没有继续提交正式的Post请求。
经过对WKWebview进行所有API的查找,没有发现相关设置。
经过基项目相关配置进行查阅,也没有相关的设置开关。
问题的症结集中在在IOS12系统的WKWebview上,接口接收到Option复杂跨域请求,正常返回后,没有继续提交正式的Post请求
这个问题上。而由上面可以初步排除通过原生的方式修改代码实现流程的贯通的办法。
于是我开始怀疑是否在IOS12系统上的WKWebview,存在对Option请求返回数据的宽容度
与其它系统存在区别?是否通过对返回数据的值进行修改,可以触发流程的贯通?
为了印证我的猜测,我做了如下的测试,最终把问题解决:
这个值的作非常重要,浏览器在接收到跨域预检
返回信息中,首先判断这个值是否有正常返回,进而进行下一步的操作。
我们对Origin的值进行了多种返回值的偿试:
*
值: 没有效果
返回请求域的值:比如api.lemacar.com,还是没有效果
这个返回值为bool数据类型,用于表示,在进行Option请示的发送时,是否把当前浏览器中存在对应该域的Cookie信息一起发送到服务端进行验证处理。
个人感觉这个值对于处理问题的作用不大,于是在偿试过true false后,和预想中的一样, 没有效果。
在进行值的偿试过程中,把这个值放到了最后,因为自己义头信息有好几个,于是我们就从简单的值开始入手。
当我们发现对上面两个值进行返回值的修改后没有效果,于是发起了一阵惊叹 “难道真的要对所有自定义头进行返回吗?”,因为我们一直用的是通配符*
作为Headers的值返回。
于是在一番折腾后,流程真的通了
在IOS12系统中,WKWebview在遇到复杂跨域请求时,也会先自动发送Option请求进行预检,但在返回的HTTP头的Access-Control-Expose-Headers字段中,不能用是通配符*作为值返回,一定要明确反回你在下一部操作中的自定义头。
同时,还可以明确一点:在IOS12系统中,WKWebview在遇到简单跨域请求时的流程是没有问题的。
所以当时前端的服务端在遇到这个问题时,就把复杂跨域请求
改成了简单跨域请求
。当然这种解决问题的办法不是长久之计。