禁用对头部异常服务器返回的HTTP响应体自动解压
解决net/http自动解压tar.gz文件导致的MD5校验与解压混乱问题
哈哈,这个坑我踩过!net/http默认的自动解压逻辑在处理.tar.gz文件时真的很闹心——本来要校验原始压缩包的MD5,结果被客户端偷偷解压了,后续操作完全乱套。别慌,有两种简单的方法能解决这个问题:
方法一:通过请求头告知服务器不要返回压缩内容
最直接的方式是在请求时设置Accept-Encoding为identity,明确告诉服务器我们只接受未压缩的原始文件,这样服务器就不会返回带Content-Encoding: x-gzip的响应了。
示例代码:
package main import ( "crypto/md5" "fmt" "io" "net/http" "os" ) func main() { url := "http://example.com/your-file.tar.gz" req, err := http.NewRequest("GET", url, nil) if err != nil { panic(err) } // 关键:要求服务器返回未压缩的原始内容 req.Header.Set("Accept-Encoding", "identity") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() // 1. 计算原始文件的MD5校验值 hash := md5.New() // 同时将内容写入临时文件,方便后续解压 tempFile, err := os.CreateTemp("", "download-*.tar.gz") if err != nil { panic(err) } defer tempFile.Close() _, err = io.Copy(io.MultiWriter(hash, tempFile), resp.Body) if err != nil { panic(err) } fmt.Printf("原始文件MD5: %x\n", hash.Sum(nil)) // 2. 解压到指定目录(这里假设解压到当前目录的output文件夹) // 这里可以用标准库的tar和gzip包正常处理,因为tempFile是原始的.tar.gz // (解压代码省略,按常规tar.gz解压逻辑编写即可) }
方法二:禁用客户端的自动解压功能
如果遇到服务器无视Accept-Encoding请求头,依然返回压缩内容的情况,可以直接禁用http.Client的自动解压功能。这需要自定义http.Transport并设置DisableCompression为true。
示例代码:
package main import ( "crypto/md5" "fmt" "io" "net/http" "os" ) func main() { url := "http://example.com/your-file.tar.gz" // 自定义Transport,禁用自动解压 client := &http.Client{ Transport: &http.Transport{ DisableCompression: true, }, } resp, err := client.Get(url) if err != nil { panic(err) } defer resp.Body.Close() // 后续的MD5校验和解压逻辑和方法一完全一致 hash := md5.New() tempFile, err := os.CreateTemp("", "download-*.tar.gz") if err != nil { panic(err) } defer tempFile.Close() _, err = io.Copy(io.MultiWriter(hash, tempFile), resp.Body) if err != nil { panic(err) } fmt.Printf("原始文件MD5: %x\n", hash.Sum(nil)) // 执行解压操作... }
注意事项
- 两种方法都能让你拿到原始的.tar.gz文件,此时你可以放心校验MD5,再用
gzip.NewReader和tar.NewReader进行常规解压操作即可。 - 方法一的效率更高,因为不需要服务器压缩、客户端再接收原始内容;方法二更稳妥,适用于所有服务器场景。
内容的提问来源于stack exchange,提问作者Milo Christiansen
相关产品推荐
相关产品推荐

