Repository navigation
feat(gateway): 支持 gzip 压缩的请求体 - #474
Merged
Merged
Conversation
Owner
|
感谢,gzip 这条路和测试都看过了。不带 合之前还想再确认两点:
另外这个分支已经落后 |
A long chat request is mostly redundant: the same system prompt, the same tool schemas, and the same indentation repeated across every message. A 60-turn history compresses ~100-300x with plain gzip. That matters when the caller reaches the gateway through a proxy with a fixed response budget. Cloudflare's 120s Proxy Read Timeout is not configurable below Enterprise, and the upload happens before the origin can answer: measured on a lossy uplink, a 1.7MB body took 133s to arrive (over budget) while its 5.4KB gzip form took 0.4s. No amount of server-side streaming can recover a request whose body never arrived. Decoding is strictly opt-in on the caller. Without a Content-Encoding header the body is read exactly as before, so clients that never compress see no behaviour change. x-gzip is accepted as the legacy alias. Two limits are enforced independently: the wire limit bounds how many compressed bytes are read off the socket, and the inflated limit bounds the decompressed bytes the JSON decoder will touch. Without the second, a small gzip body could expand without limit. An unrecognised encoding answers 415 naming the encoding, rather than surfacing as a JSON syntax error.
caigee-cmd
force-pushed
the
feat/gzip-request-bodies
branch
from
November 8, 2026 06:57
5e82c46 to
2d59b8d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
长对话的请求体高度冗余:同样的 system prompt、同样的工具 schema、同样的缩进在每条消息里重复。实测 60 轮历史用普通 gzip 能压 100-300 倍。
为什么值得做
当调用方经由带固定响应预算的反向代理访问网关时,这个体积是致命的。Cloudflare 的 120 秒 Proxy Read Timeout 非 Enterprise 不可调,而上传发生在服务端能开始工作之前:
在丢包严重的家宽链路上实测,同一个 1.7MB 请求体:
这跟上游快慢无关——body 没到齐,服务端连请求都还没拿到,任何服务端流式输出都救不回来。
做法
POST /v1/chat/completions、/v1/messages、/v1/responses三个入口接受Content-Encoding: gzip(x-gzip作为旧别名一并接受)。解码严格由调用方选择:不带这个头的请求读取方式完全不变,不压缩的客户端零感知。所以这个改动对现有用户是纯增量。
两个独立的上限
没有第二个上限,一个小体积的 gzip body 可以无限膨胀(zip bomb)。
错误语义
网关不认识的编码返回 415 并指明编码名,而不是把 zstd 之类的字节丢给 JSON 解析器、最后报一个让人摸不着头脑的语法错误。
验证
request_body_test.go覆盖 8 个场景:gzip 解码、明文路径不变、未知编码 415、损坏 gzip 400、解压上限、identity透明、x-gzip、以及 Anthropic 和 Responses 两个端点。端到端实测(真实模型,40 轮对话,122KB body → 883 字节):
明文与 gzip 两条路径产出的
prompt_tokens完全相同,确认服务端完整还原了请求。go build ./... && go test ./internal/gateway/全绿。说明
服务端这半边是前提,客户端也需要压缩请求体才能拿到收益。这个 PR 只做服务端解码;不改的客户端行为完全不变。
Huffman/gzip 是 stdlib 里的,没有新增依赖。
本 PR 由 AI 辅助生成与测试,提交前已人工审阅。