Golang http response 解压缩分析

Golang自带的 http 标准库一直是自己的首选http library,最主要的原因是对标准的细节支持非常到位,兼容性优秀。

前几天遇到一个问题一直没时间处理,晚上花了挺多时间排查,落实到代码上其实也就一行的修改量,但是对于有段时间没有读标准库代码的自己来说倒是值得记录一下。

问题

使用标准库进行 http 请求时,如果在请求 header 中手动设置了 Accept-Encoding, 那么返回的响应内容看起来是乱码(其实是二进制)。

原因

定位的过程其实挺曲折的,分析抓包的时候对比了多个请求数据,最终才确认是header 中的 Accept-Encoding 导致。而这个细节之前在 http.Transport 的 DisableCompression 字段是有文档说明的:

也就是说:

  • 如果设置 DisableCompressiontrue 并且请求中没有设置 Accept-Encoding 的情况下,那么将发送要求服务器返回非压缩的请求;如果 DisableCompressionfalse (默认值), 则会发送允许服务器返回压缩内容的请求,并且会在 transport 层自动把 response 内容解压返回到业务层。这一点很容易理解,屏蔽了解压读取压缩内容细节,使用起来也非常方便。这也是我对golang http 标准库的理解,很多东西都自动处理了。我遇到的问题在于下面说的第二点。
  • 如果用户手动在请求中设置了 Accept-Encoding, 那么标准库会认为业务层是想自己接管 response 内容的处理,因此会返回原始的未解压的内容。也就是上面问题里面提到的乱码数据。

这段话看起来比较绕,我们直接看一下 transport.go 相关代码。

发起请求时,DisableCompressionfalse 且业务层没有设置 Accept-Encoding 的情况下,自动设置header:

读取 response 时,解压内容:

小结

很多问题其实都是魔鬼在细节中,本质上还是基础文档没有仔细阅读。不过找问题的晚上其实也挺开心的,因为通过配置好的 github Copilot 来写代码,整个过程真的非常愉悦。最开始自己还会写几个关键字,引导 Copilot 给出提示代码,后面索性回车就开始等待 Copilot 帮我写代码,跟自己编写代码匹配度能到 80% 以上。目前已知的不足是在 string 的内容推导上有时候不太准确(事实上,人工编码的时候,这部分也容易出现typo或者其他错误),因此要注意这部分代码的review.