引子
我们开发了一款微信小程序,但是上线的时候遇到了很奇怪的事情:在iOS端有时能访问,有时不能访问;在Android端完全不能访问。我们的后端服务部署在校内服务器,在外部通过xxx.xxxx.xxx.xx访问。在电脑端不管是使用接口测试工具还是浏览器访问,我们的后端都是正常可访问的。
深入
前端同学利用小程序调试工具,最早向我们反馈了可能是证书问题。由于手头没有小程序的源码,我自己动手写了一个demo复现这个错误。复现的代码非常简单,就是发起一个HTTPS请求,并把响应体打印在控制台。整个复现过程非常顺利,同样的错误也出现了,这次我看到了控制台输出的详细错误,错误代号-2:net::ERR_FAILED。其实这个时候就初步判断不是应用层的问题了,问题至少出在网络层或运输层。
1 | // 与此问题关联的核心代码 |
请注意图中黄色部分,红色部分与此问题无关。
回想到整个业务的网络拓扑结构,由于内网环境的特殊性,还部署了WAF过滤请求,用户端不是直接与服务端进行交互,这中间还涉及到内网内部的转发,因此还需要进一步证实具体问题。

简化的网络拓扑结构如上图所示。我们在应用服务器上找到了前几次访问的日志,尽管在小程序上没有得到响应,日志显示这些请求被正常响应并返回,这意味着用户发出的请求通过了网关,被核心路由正确转发到了应用服务器,我们的应用服务器也做出了正确的响应。至此可以判断,问题只能出在是网关及以外的地方。
为了查看请求从用户设备到网关直接到底发生了什么情况,我对手机进行了抓包分析,使用的工具是charles。
Charles使用自签名证书实现中间人嗅探,从而实现侦听SSL请求。奇怪的是,进行抓包的时候请求一切正常,以TLS1.2协议握手成功,手机上也能访问了。因此初步判断问题还是出在了证书上,使用charles抓包时,证书信任过程不再交给手机处理。自然而然地我想到,如果手机上根本不发出HTTPS请求会怎样?
为了验证SSL证书和这个错误的关系有多大,我将小程序中网络请求降级为HTTP,在真机验证一切正常。但由于微信要求所有请求必须为HTTPS,所以这个问题不能以降级为HTTP的方式解决。
证书的再验证
微信官方提示使用myssl.com进行证书检测,该网站始终认为我们的证书没有问题,这也是解决这个问题耗费如此长时间的原因。在所有证据均指向证书错误以后,我们改用其他工具重新测试证书,果然发现了问题。
myssl.cn上检测提示,服务器中间证书缺失。
结论
我们认为,问题可能出在网关上的SSL证书配置有误,遗漏了中间证书。对绝大部分电脑浏览器而言,缺失的中间证书会自动补全,不影响访问。而小程序中的全部网络请求基于腾讯X5内核实现,根据Android平台的特点及安全性考虑(请求伪造和中间人攻击),腾讯有可能在软件层面屏蔽了证书链缺失的HTTPS响应,这也就造成了无法访问的假象。
后续
经机房人员查证,问题出在WAF上的HTTPS防护功能,在设备厂家研发人员的指导下调整恢复正常。
本文作者:MyTech::Author