当前位置: 首页 > 科技观察

问题排查从错误码406

时间:2023-03-21 22:34:36 科技观察

后台前段时间突然接到操作同事反映,沪江老师在国外无法登录沪江账号。这是一个很常见的故障,但是排查过程并不简单,我们在一次偶然中收获颇丰,在此分享给大家。我们首先判断,从故障现象来看,应该与后台无关,而是与前端有关,于是赶紧查看了前端的日志。从日志来看,主要是用来判断客户端的地理位置接口。出现大量HTTPStatusCode406(24小时内出现1w多条)。根据HTTPStatusCode规范,以4开头的错误码与客户端有关。考虑到该故障只发生在一位老师身上,初步判断406为问题根源。随着我们掌握的信息增多,分析的深入,我们很快解决了外教的错。不幸的是,我们确认它与406无关。但是,我们不能就此止步。毕竟正常情况下,响应的HTTPStatusCode应该是200,那么大量的406到底是什么?为什么我们不能复制它们?他们是怎么造成的?如此大量的爆发应该引起用户的反馈?为什么在线为什么反馈如此平静?下图是日志平台406错误的排查流程。为了保证性能,我们的Node端并没有详细记录每一个请求,所以我们不能简单的看406日志就知道具体原因。为了解决这个问题,我们紧急发布了一个在线补丁,记录了每个请求的详细信息,然后在日志平台中看到了如下请求。为了对比,我们在浏览器上拦截了正常的请求。仔细比较下图两个请求,结合错误码406的定义,我们把注意力集中在Accept头日志和正常的浏览器行为上,于是,我们在Postman中模拟了错误的请求,果然,我们重现了406错误,所以可以确认问题出在Accept字段。406NotAcceptable状态码表示客户端错误,表示所请求资源的内容特征不能满足请求头中的条件,因此无法生成响应实体。翻译自HTTP协议规范的RFC文档。我们在网上查了资料,和后端同事一起讨论406错误码。我们了解到,如果请求头中的Accept不符合之前约定的约定,就会返回406错误。API服务报错,返回application/json格式的数据,但是请求中的Accept表示不支持这种格式,所以会报406错误。我们仔细检查了常见浏览器发送的请求,发现它们都包含Accept:*/*;。看起来这些406请求不是来自普通用户。那么,这些要求是谁提出的呢?会不会是CDN?CDN的全称是ContentDeliveryNetwork,即内容分发网络。其目的是使用户就近获取所需内容,解决Internet网络拥堵情况,提高用户访问网站的响应速度。CDN网络可以将服务器的内容缓存到分布在世界各地的CDN节点,根据用户的访问IP连接就近的CDN,提高网站响应速度。(转自google.com)现在CDN是各个公司的通用配置,沪江也不例外。我们仔细研究了导致406的请求的源IP,发现都是来自北京联通的几个节点。从这一点来看,CDN非常可疑,大概有两种可能:1、原请求头中的Accept字段错误;2、原请求头中的Accept字段是正确的,但是在经过CDN节点时被阻塞了。CDN被篡改。由于之前遇到过CDN篡改header的问题,初步判断是CDN的问题。接下来,我们暂时将北京联通节点回源,验证CDN是否篡改了header,同时获取了最终的用户IP。在网上搜索这个IP的详细信息,上面写着某搜索引擎的爬虫。原来406不是来自普通用户,而是搜索引擎的爬虫。花絮在写文章的这几天,发现错误日志下降了很多,406错误也没有了。以为是某个搜索引擎反悔了,于是在当时IP错误的日志平台上搜索了一下,发现只是搜索引擎改变了策略而已。修改了Accept字段,在UA头中加入了搜索引擎的独有标识,变身为常规搜索引擎。小结对于开发者来说,当网站遇到大量406错误时,不用太担心。仔细检查日志。它很可能是由搜索引擎爬虫引起的。总结这次406错误码事件,是某搜索引擎在爬取沪江页面时,请求头设置Accept与后台服务接受的Accept字段不一致,导致出现大量406错误。***详细讲解Header中Accept的相关知识。Acceptheader使用它来通知客户端可以处理的内容类型。这种内容类型用MIME类型表示(引用自MDN)contenttypetext/html,application/xhtml+xml和application/xml都是MIME类型,也可以称为媒体类型和内容类型。在示例中,application是类型,json是子类型。它表明客户端只能接收application/json类型的响应。如果服务器不能返回这种类型的响应,服务器应该返回一个406错误。通配符*代表任何类型。例如:Accept:/表示浏览器可以处理所有类型。Accept可以支持以.分隔的多种类型。响应头通知客户端它的选择。显示客户端能收到的响应只有三种类型:text/html、application/xhtml+xml、application/xml。因子权重(q)q是0-1之间的一个值,q的默认值为1,q=0表示不可接受,q的值越大,请求越倾向于获取之前类型所代表的内容“;”说明客户端更喜欢text/html格式的响应,其次是application/xhtml+xml,最后是application/xml,*/*。