发布于2026-07-29 阅读(0)
扫一扫,手机访问
先来重温一下核心原理:上行请求体压缩并不是HTTP库自带的功能,本质上是你自己把body做gzip压缩,然后带上 Content-Encoding: gzip 请求头,把压缩后的二进制数据当作请求体发出去。

所有支持自定义请求body和自定义请求头的HTTP客户端都能实现,区别无非是各个库的参数名不同:
data=content=data=data=POSTFIELDS下面分「同步库」「异步库」给出完整示例,统一复用同一个gzip压缩函数。
通用压缩工具函数(所有示例共用)
import gzip
from io import BytesIO
def gzip_compress(raw_bytes: bytes) -> bytes:
buf = BytesIO()
with gzip.GzipFile(fileobj=buf, mode="wb") as f:
f.write(raw_bytes)
return buf.getvalue()
如果环境受限不能装第三方包,用urllib就行,不用额外安装任何东西。
import json
from urllib import request
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
headers = {
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
req = request.Request(url, data=compressed_body, headers=headers, method="POST")
with request.urlopen(req) as resp:
print(resp.read().decode("utf-8"))
不过说实话,它的API比较简陋,不支持连接池,超时处理也不够友好,生产环境一般不会首选它。
新一代HTTP客户端,风格和requests很像,而且同时支持HTTP/1.1和HTTP/2。
import httpx
import json
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
headers = {
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
# 同步
with httpx.Client(timeout=10) as client:
res = client.post(url, headers=headers, content=compressed_body)
print(res.text)
# 异步版本
"""
import asyncio
async def run():
async with httpx.AsyncClient(timeout=10) as client:
res = await client.post(url, headers=headers, content=compressed_body)
print(res.text)
asyncio.run(run())
"""
注意:httpx 传二进制body的参数名是 content,不是data,容易搞混。
异步生态里的标准HTTP客户端,爬虫和异步微服务大量使用它。
import aiohttp
import asyncio
import json
async def main():
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
headers = {
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
async with aiohttp.ClientSession() as session:
async with session.post(url, data=compressed_body, headers=headers) as resp:
print(await resp.text())
asyncio.run(main())
基于C库libcurl,吞吐性能极强,适合超高并发场景;但缺点也很明显:Windows安装麻烦,API比较晦涩。
import pycurl
import json
from io import BytesIO
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
resp_buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.POST, 1)
c.setopt(c.POSTFIELDS, compressed_body)
c.setopt(c.WRITEDATA, resp_buffer)
headers = [
"Content-Type: application/json; charset=utf-8",
"Content-Encoding: gzip"
]
c.setopt(c.HTTPHEADER, headers)
c.perform()
c.close()
print(resp_buffer.getvalue().decode())
如果项目本身在用Tornado Web框架,直接用内置的客户端就行,不用额外引入依赖。
import json
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
import tornado.ioloop
async def fetch():
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
req = HTTPRequest(
url,
method="POST",
body=compressed_body,
headers={
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
)
client = AsyncHTTPClient()
res = await client.fetch(req)
print(res.body.decode())
tornado.ioloop.IOLoop.current().run_sync(fetch)
不要使用框架自带的json参数:比如 httpx.post(json={})、requests.post(json={}),这类接口会自动编码,你没法替换成压缩二进制。必须手动序列化,然后用原始body参数传。
下行压缩 ≠ 上行压缩:
Accept-Encoding 只是告诉服务端:我能接收压缩响应;Content-Encoding: gzip 才代表:本次请求body已经压缩了。服务端必须手动解压:绝大多数Web框架默认不会自动解压带有Content-Encoding的请求体,如果服务端没有解压代码,收到的是乱码二进制。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8