近期项目中遇到一个bug,其中解决过程比较有意思,特此记录下来。有一天看到报警记录有一个500服务端的错误,量不多,一周都不必定有一个,先根据服务器里的本地日志拿到了当时请求的相关信息像UA、cookie什么的,肯定了请求是来自iPhone上的qq浏览器,由于咱们业务在手机浏览器里没有入口,因此这种状况不多。因而找来iPhone下载QQ浏览器尝试复现问题。ios
描述:iPhone中某些版本的QQ浏览器中提交订单时,报错提示服务端异常,经抓包排查发现提交订单时post请求的body为空,content-length为0,因而开始了此次艰难蛋疼的bugfix过程。浏览器
其中手机是iPhone 8p,QQ浏览器版本9.1.0.4110,ios版本11.0,请求UA是Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0 MQQBrowser/9.1.0 Mobile/15B87 Safari/604.1 MttCustomUA/2 QBWebViewType/1 WKType/1。(虽然这些对此次后期排查修复都没什么蛋用,但有时仍是颇有用的)。服务器
我的喜欢debug时用排除法,先肯定问题所在cookie
首先排查发post请求过程有没有问题,由于有可能依赖的某个包在国产QQ浏览器上有兼容性问题,但一路排查发起过程都没什么问题,最后不用依赖包,直接用XMLHttpRequest手写了个post请求依然很差使,排除了发请求的依赖包的问题。数据结构
排查项目是否对发请求有影响,有些内部的监控上报的包可能会对XMLHttpRequest中方法作改写,因而一路删除怀疑的依赖包,最后单纯返回了一个简单页面,页面内发一个post请求,body依然为空,至此排除了全部依赖包的影响(这个过程很费时间,这个思路不是很好)。frontend
排查到这就有点蛋疼了,Google搜了下看有没有人和我遇到一样的问题,发现qq浏览器论坛上17年就有人提出这个问题了,类似的帖子大概有七八个,但有官方回应的也就一两个,回复也只是说让升级浏览器。。。用户升级浏览器还行,开发者得解决问题啊,排查到这已经肯定了一点,就是qq浏览器确定对post请求的支持是有问题的。post
意识到qq浏览器有问题,下意识想针对qq浏览器作下兼容处理。开始想post改为get请求,可是post中的body不是简单地数据结构,若是是如下数据改为get还好,如:测试
body
{
name: 'frontend',
age: '8',
}
复制代码
可是遇到较为复杂的数据结构就很差使了,如:spa
{
times: [123,234,2423,12],
favour: {
detail: 'sdadfa',
}
}
复制代码
由于改为get后是经过query来传递数据的,query是只支持字符串的;另外这种方式隐隐约约感受会坑很大,因此排除了这种方式。因而尝试另外一种方式,把body数据放到header里面,反正HTTP协议里对header大小是没作限制的,因此这样干的debug
const xhr = new XMLHttpRequest();
xhr.setRequestHeader({
x-body: JSON.stringify(body),
})
复制代码
服务端接收时再判断header中是否有x-body,当时想的这种方式是可行的,但现实很残酷,这种方式测试时发现抓包都抓不到,说明请求都没发出来,把body数据改小点,测试是能够的,这说明qq浏览器对header里数据大小是有限制的,(这就是理论与现实的矛盾的问题,http协议其实对这些都是没有限制的,但各个浏览器会有各自不一样的限制),这种方式也宣布流产,此时已经中度蛋疼了。
问题就是qq浏览器中post请求时body为空,须要在页面返回时有content-type,不然在一些版本的qq浏览器中会识别有问题,致使body为空。
在这个过程当中,我意识到两个问题