任何恐惧都来源于不了解。
最近发现了一个问题,有用户反馈,整个APP里面所有的h5页面全部打不开,这个结果无疑是恐怖的,因为我们的APP,从产品详情到收银台,从促销页面到会员服务都是h5,全站打不开的结果当然是恐怖的。通过查看用户日志,发现webview报了一个很固定的错误:
NSCocoaErrorDomain-Error Domain=kCFErrorDomainCFNetwork Code=303 "(null)" UserInfo={_WKRecoveryAttempterErrorKey=, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <8A39DFD8-99CD-4E21-B7CC-E90D9A61471C>.<15>, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2205}
这个错误日志中最有价值的部分是:kCFErrorDomainCFNetwork Code=303。那么这个大名为303的错误究竟为何?你可以很快在Apple的官网(https://developer.apple.com/documentation/cfnetwork/cfnetworkerrors/cferrorhttpparsefailure)上找到结果:
根据Apple的解释,这个错误发生的原因是解析服务端响应错误。将问题反馈给服务端,结果服务端查了一圈,根本没有收到请求,既然没有收到请求,这个响应解析错误的原因从服务端无法查起,只能在客户端去定位,此时第一时间想到了缓存。是不是webview缓存了什么公共的东西出现了错误,导致每次请求直接失败。此时恰好有个内部同事反馈了同样的问题,我们引导该同事重新进行了登录,结果发现问题解决了,这更进一步的印证了我们的猜测,是不是cookie有问题?因为退出登录时会清理cookie。此时虽为明确问题原因,但好在也解决了一个case,后续多少有些解决方法可以提供了。
问题还在延续,通过监控,发现每天几乎有上千名客户被影响,此时又有用户反馈问题,将前述解决方案同步给了客服,结果客服反馈,重新登录并未解决问题,后来是用户卸载重新安装应用才解决了问题。这个事实说明了一个问题,前面的猜测可能有问题,所以,这里也给了客服应对的话术:如果有问题反馈,可以让用户重装APP来解决。虽然这个方式真的很蠢,也对用户不够友好,但是实在没有别的办法可以解决,因为问题的原因并不明朗。
正在一筹莫展之际,安卓端也出现了大量的用户反馈,页面无法打开,我们的安卓端使用了腾讯的X5内核,报错时有明显的信息提示给了用户,通过用户的截图与腾讯X5内核的同事进行了交流,结论是所报错误的原因为:服务端关闭了连接。服务端通过这个信息进一步进行了排查,结果发现出问题时是因为当前的http请求header过大,超过了阈值(我们的服务端默认阈值为4k),所以服务器直接拒绝了该访问。这个原因和X5呈现的原因完全一致。而http header中最大的部分是我们的UA(这里由于历史的原因,我们的UA承担了本不应该由它承担的任务)。
我们迅速的在iOS端进行了复现,将UA扩大到4k以上,结果成功复现问题,此时返回的就是303。至此,这个问题基本明确了,由于请求头过大导致服务端拒绝了请求,这也可以解释为什么出现问题后全站h5均无法加载,也可以解释为什么有些用户清理一下cookie问题可以解决(cookie减小,http header也会减小),当然也可以解释为什么重装设备可以解决问题。后续UA增大原因的排查以及后续的处理这里不再赘述了,完全是体力活儿。
经验:
iOS端排查问题不顺利主要是被错误原因干扰了,导致排查方向出现了偏差。而且我们还发现了一篇Mac的售后服务文档https://www.mactechnicalsupportphonenumber.com/blog/how-to-fix-kcferrordomaincfnetwork-error-code-303-on-safari/,这里提到了303的错误是Safari自身的错误,这就更加坚定了我们在错误的道路上越走越远。
服务端拒绝访问竟然没有日志,这是一个很大的问题,如果服务端可以将拒绝访问或者其他的异常情况进行日志统计并形成告警机制,这个问题也不会蔓延到这个程度而整个公司不知。埋点、数据、监控在互联网的每个环节真的都很重要!!!
最后,作为webview,设计架构webview时一定要考虑清楚数据的通信机制,莫拿UA、cookie等机制去做不该做的事情,最终的结局只能是自食恶果。后续,我们的UA一定要清理掉不必要的东西。