fix(compression): 跳过已有 Content-Encoding 的响应压缩
当上游处理器(如 gzip_static)已设置 Content-Encoding 时, 跳过压缩避免双重编码导致数据损坏。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
3202993a48
commit
f507fe0951
@ -192,6 +192,12 @@ func (m *Middleware) Process(next fasthttp.RequestHandler) fasthttp.RequestHandl
|
||||
// 执行处理器
|
||||
next(ctx)
|
||||
|
||||
// 检查是否已有 Content-Encoding(由 gzip_static 或上游处理器设置)
|
||||
// 已编码的响应不应再次压缩,避免双重编码导致数据损坏
|
||||
if len(ctx.Response.Header.Peek("Content-Encoding")) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取响应体
|
||||
body := ctx.Response.Body()
|
||||
bodyLen := len(body)
|
||||
|
||||
@ -475,3 +475,77 @@ func TestProcessSmallResponseBuffered(t *testing.T) {
|
||||
t.Errorf("Expected compressed body smaller than original, got %d >= %d", len(body), len(smallResponse))
|
||||
}
|
||||
}
|
||||
|
||||
// TestMiddleware_SkipPrecompressed 验证预压缩响应不被再次压缩。
|
||||
// 当上游处理器(如 gzip_static)已设置 Content-Encoding 时,
|
||||
// compression 中间件应跳过压缩,避免双重编码导致数据损坏。
|
||||
func TestMiddleware_SkipPrecompressed(t *testing.T) {
|
||||
m, _ := New(&config.CompressionConfig{
|
||||
Type: "gzip",
|
||||
Level: 6,
|
||||
MinSize: 1,
|
||||
})
|
||||
|
||||
// 模拟预压缩响应(如 gzip_static 设置的)
|
||||
originalBody := []byte("precompressed data")
|
||||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||||
ctx.Response.SetBody(originalBody)
|
||||
ctx.Response.Header.Set("Content-Encoding", "gzip")
|
||||
ctx.Response.Header.SetContentType("application/json")
|
||||
}
|
||||
|
||||
handler := m.Process(nextHandler)
|
||||
|
||||
ctx := &fasthttp.RequestCtx{}
|
||||
ctx.Request.Header.Set("Accept-Encoding", "gzip")
|
||||
|
||||
handler(ctx)
|
||||
|
||||
// 验证 Content-Encoding 保持不变
|
||||
encoding := ctx.Response.Header.Peek("Content-Encoding")
|
||||
if string(encoding) != "gzip" {
|
||||
t.Errorf("Content-Encoding = %q, want %q", string(encoding), "gzip")
|
||||
}
|
||||
|
||||
// 验证 body 内容未被修改(未被再次压缩)
|
||||
body := ctx.Response.Body()
|
||||
if !bytes.Equal(body, originalBody) {
|
||||
t.Errorf("Body was modified, should remain unchanged")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMiddleware_CompressWhenNoPrecompressed 验证无预压缩文件的响应仍正常压缩。
|
||||
func TestMiddleware_CompressWhenNoPrecompressed(t *testing.T) {
|
||||
m, _ := New(&config.CompressionConfig{
|
||||
Type: "gzip",
|
||||
Level: 6,
|
||||
MinSize: 1,
|
||||
Types: []string{"application/json"},
|
||||
})
|
||||
|
||||
// 使用足够大的数据确保压缩后更小
|
||||
originalBody := bytes.Repeat([]byte(`{"message": "test"}`), 100) // ~1700 bytes
|
||||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||||
ctx.Response.SetBody(originalBody)
|
||||
ctx.Response.Header.SetContentType("application/json")
|
||||
}
|
||||
|
||||
handler := m.Process(nextHandler)
|
||||
|
||||
ctx := &fasthttp.RequestCtx{}
|
||||
ctx.Request.Header.Set("Accept-Encoding", "gzip")
|
||||
|
||||
handler(ctx)
|
||||
|
||||
// 验证 Content-Encoding 被设置
|
||||
encoding := ctx.Response.Header.Peek("Content-Encoding")
|
||||
if string(encoding) != "gzip" {
|
||||
t.Errorf("Content-Encoding = %q, want %q", string(encoding), "gzip")
|
||||
}
|
||||
|
||||
// 验证 body 被压缩(大小应该变小)
|
||||
body := ctx.Response.Body()
|
||||
if len(body) >= len(originalBody) {
|
||||
t.Errorf("Expected compressed body smaller than original, got %d >= %d", len(body), len(originalBody))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user