http status code 431
这周末处理一个 http status code 431 的 case. 431 表示 header 字段的数据太大, 听起来也没那么复杂, 就是消减一下 header 内容就解决了. 但是在大家都说最近没有任何改动的情况下, 到底哪里出问题了呢?
431 表示什么?
从 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431 介绍看. 有 2 种可能的情况:
- 所有 header 的字段数据加起来太大了;
- 单个 header 的字段数据太大了;
谁会报这个错?
听起来这个问题有点多余, 当然是应用服务器了. 其实不然. 中间可以拆包的所有网络组件都有可能, 比如: 可以拆包的代理, 负载均衡服务器, 如今应用广泛的反向代理服务器 envoy, nginx 等. 他们都可以拆开 http 的报, 检查一下 header 的大小, 然后报个 431 给客户端.
例子
下面便是当时的一个例子, 把其中一个字段加大到60多KB. 可以看到 header 是431, response payload 是一句话.
这个例子是 envoy 拆包后发现 header 很大, 根据 envoy 官方文档: max_request_headers_kb, 它不会验证单个 header 大小, 而是验证整个header 大小. 默认是60K, 所以这里超了.
网络链路添加 header
通常情况下, 做为客户端发出的所有 header 就是服务器端收到的所有 header, 但是这些中间会拆包的各个组件其实都有可能添加新的 header 到原始的数据报文中. 比如: 一般负载均衡服务器会添加一个 header 告诉下游服务器真正的客户端的 IP 是多少, 这样下游服务器就知道真正的客户IP 是多少了? 否则它通过 remote IP 获得的就是负载均衡服务器的IP.
有时候, 中间拆包的组件可能会添加更多的 header 用来输送更多的信息给下游, 比如: 当前拆包的组件名称, 它的IP, 它的版本之类的.
如何区分到底是最终应用服务器返回431 还是中间拆包组件?
通常情况下, 这些不同的组件或者应用服务器返回的 response header 里面会标明它的身份. 比如我们的例子中它就是中间的 envoy 组件返回的, 不是最终的应用服务器. 应用服务器会返回带不同 header response.
为什么 header 会很大?
各种原因都会有, 比如:
- Referer 是一个巨长的 URL.
- Cookie 的内容太多 (Cookie 的内容都是header里面的)
- 某个 header 添加了巨多内容.
具体在我们这个case 里面, 就是客户端有个小系统, 它为了不让下游子系统去到一个远程系统取很多数据, 直接把这部份内容放到 header 发给下游了, 然而这部份内容是一个动态变动的部分, 就像一个list, 会随着系统增加减小, 正巧它这次很大, 就遇到这种情况.