content-encoding relate problem
问题
工作中,使用 nextJs 代理请求是,发现浏览器端数据为空,但是 curl 有数据,经排查,node 端也是有数据的,最终发现是因为请求使用了 gzip 压缩,而转发请求的时候,没有进行响应头处理,导致浏览器端收到已经解压的数据后,仍然以为数据未解压。
解决
移除 content-encoding 响应头和content-length 响应头
解释
关于 content-encoding 的工作原理:
HTTP 压缩机制:
当服务器发送响应时,为了减少传输数据大小,使用了 gzip 压缩
这体现在响应头:content-encoding: gzip
这表示响应体是经过 gzip 算法压缩的双重解压的问题:
在我们的代理服务器中,fetch API 已经自动处理了 gzip 解压缩
但是我们保留了原始的 content-encoding: gzip 头
当这个响应转发到浏览器时,浏览器看到 content-encoding: gzip,会尝试再次解压缩
但数据已经被 fetch 解压过了,所以浏览器解压时会失败或得到错误的数据解决方案:
1
2
3const responseHeaders = new Headers(response.headers)
// 移除 content-encoding 头,因为我们会自动处理解压缩
responseHeaders.delete('content-encoding')
通过删除 content-encoding 头,我们告诉浏览器这是未压缩的数据
这样浏览器就会直接使用数据,而不会尝试解压缩
数据流程:
1
2
3
4
5原始流程:
服务器(压缩数据 + gzip头) -> 代理(自动解压) -> 浏览器(尝试解压已解压的数据) ❌
修改后流程:
服务器(压缩数据 + gzip头) -> 代理(自动解压 + 移除gzip头) -> 浏览器(直接使用) ✅为什么 fetch 会自动解压:
Node.js 的 fetch API 默认会处理常见的内容编码(如 gzip、deflate)
这是为了简化开发者的使用体验
当它看到 content-encoding: gzip 时,会自动解压数据,但不会自动移除这个头
这就是为什么删除 content-encoding 头能解决问题 - 它避免了数据被重复解压缩的问题,确保了数据在整个传输链路中只被解压缩一次。
content-encoding relate problem
https://www.hanwei.ink/2024/12/09/content-encoding-relate-problem/