Python中HTTP请求体压缩的实现方法

 更新时间:2026年07月29日 08:27:56   作者:detayun  
日常开发中使用 Python 调用 HTTP POST 接口时,如果上传报文体积较大,未压缩的数据会占用更多带宽,增加网络耗时,高并发场景下还会提升服务器流量压力,本文讲解 HTTP 请求体压缩原理,提供 requests、httpx、aiohttp 完整实现代码,需要的朋友可以参考下

前言

日常开发中使用 Python 调用 HTTP POST 接口时,如果上传报文体积较大(大量 JSON、批量数据、文本内容),未压缩的数据会占用更多带宽,增加网络耗时,高并发场景下还会提升服务器流量压力。

很多开发者熟悉服务端返回压缩响应(Accept-Encoding),却很少了解:客户端同样可以将请求 Body 压缩后上传

本文讲解 HTTP 请求体压缩原理,提供 requestshttpxaiohttp 完整实现代码,并梳理常见踩坑点。

关键概念区分

  • Accept-Encoding: gzip, deflate:告诉服务端,客户端支持接收压缩响应(下行压缩,绝大多数库自动支持)
  • Content-Encoding: gzip:告诉服务端,当前 POST 请求 Body 已经被压缩(上行压缩,需要手动实现)

重要前提:服务端必须实现对应解压逻辑。若后端没有处理 Content-Encoding 请求头,直接接收压缩二进制流会出现解析报错。

一、实现原理

  1. 将原始报文(JSON/二进制文本)序列化为字节;
  2. 使用 gzip/deflate 算法压缩字节数据;
  3. 请求头增加 Content-Encoding: gzip
  4. POST 使用 data / content 参数传入压缩后的二进制,禁止使用 json 参数
  5. HTTP 自动填充 Content-Length,无需手动计算。

推荐算法:gzip,跨语言、各后端框架兼容性最优。

二、requests 同步实现(最常用)

import requests
import gzip
import json
from io import BytesIO

def gzip_compress(raw_data: bytes) -> bytes:
    """gzip压缩字节数据"""
    buffer = BytesIO()
    with gzip.GzipFile(fileobj=buffer, mode="wb") as fp:
        fp.write(raw_data)
    return buffer.getvalue()

if __name__ == "__main__":
    url = "http://127.0.0.1:8000/api/upload"
    payload = {
        "list": list(range(2000)),
        "content": "大量测试文本" * 500
    }

    # 序列化为JSON字节
    raw_bytes = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    
    # 阈值判断:过小的数据不压缩,避免压缩头部导致体积变大
    compress_threshold = 2048
    headers = {
        "Content-Type": "application/json; charset=utf-8"
    }
    if len(raw_bytes) > compress_threshold:
        body = gzip_compress(raw_bytes)
        headers["Content-Encoding"] = "gzip"
    else:
        body = raw_bytes

    resp = requests.post(url, headers=headers, data=body)
    print("状态码:", resp.status_code)
    print("响应内容:", resp.text)

避坑:不要使用 requests.post(..., json=payload)
json 参数内部会自动编码,无法传入压缩后的二进制数据,必须使用 data

三、httpx 同步/异步实现(新项目推荐)

import httpx
import gzip
import json
from io import BytesIO

def gzip_compress(raw_data: bytes) -> bytes:
    buffer = BytesIO()
    with gzip.GzipFile(fileobj=buffer, mode="wb") as fp:
        fp.write(raw_data)
    return buffer.getvalue()

def sync_request():
    url = "http://127.0.0.1:8000/api/upload"
    payload = {"data": list(range(3000))}
    raw_bytes = json.dumps(payload).encode("utf-8")
    compressed = gzip_compress(raw_bytes)

    headers = {
        "Content-Type": "application/json; charset=utf-8",
        "Content-Encoding": "gzip"
    }
    with httpx.Client() as client:
        r = client.post(url, headers=headers, content=compressed)
        print(r.status_code, r.text)

# 异步版本
import asyncio
async def async_request():
    url = "http://127.0.0.1:8000/api/upload"
    payload = {"data": list(range(3000))}
    raw_bytes = json.dumps(payload).encode("utf-8")
    compressed = gzip_compress(raw_bytes)

    headers = {
        "Content-Type": "application/json; charset=utf-8",
        "Content-Encoding": "gzip"
    }
    async with httpx.AsyncClient() as client:
        r = await client.post(url, headers=headers, content=compressed)
        print(r.status_code, r.text)

if __name__ == "__main__":
    sync_request()
    # asyncio.run(async_request())

四、aiohttp 异步实现

import aiohttp
import asyncio
import gzip
import json
from io import BytesIO

def gzip_compress(raw_data: bytes) -> bytes:
    buffer = BytesIO()
    with gzip.GzipFile(fileobj=buffer, mode="wb") as fp:
        fp.write(raw_data)
    return buffer.getvalue()

async def main():
    url = "http://127.0.0.1:8000/api/upload"
    payload = {"data": list(range(3000))}
    raw_bytes = json.dumps(payload).encode("utf-8")
    compressed_body = gzip_compress(raw_bytes)

    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("status:", resp.status)
            print(await resp.text())

if __name__ == "__main__":
    asyncio.run(main())

五、配套服务端简易解压示例(FastAPI)

测试时需要后端支持解压,附上最简示例:

from fastapi import FastAPI, Request
import gzip
import json
from io import BytesIO

app = FastAPI()

@app.post("/api/upload")
async def upload(request: Request):
    headers = request.headers
    body = await request.body()
    # 判断是否gzip压缩
    if headers.get("Content-Encoding") == "gzip":
        buf = BytesIO(body)
        with gzip.GzipFile(fileobj=buf) as f:
            body = f.read()
    data = json.loads(body)
    return {"msg": "接收成功", "data": data}

六、常见问题与优化建议

1. 小数据不要强行压缩

gzip 自带固定头部(十几字节),报文很小的时候,压缩后体积可能大于原始数据。建议设置阈值(2KB左右),超过阈值再开启压缩。

2. Content-Type 不要删除

Content-Encoding 只是标记编码方式,不能替代 Content-Type。JSON 请求依旧保留 application/json

3. 代理、网关兼容性问题

部分老旧反向代理、防火墙不识别 Content-Encoding,可能直接丢弃请求。上线前务必做连通性测试。

4. 区分上行压缩与下行压缩

很多人混淆两个头:

  • Accept-Encoding:客户端声明能接收压缩响应(下载)
  • Content-Encoding:请求体已经压缩(上传)

requests、httpx 默认自带 Accept-Encoding,响应自动解压,无需手动处理。

5. 二进制文件场景

不仅限于 JSON,上传文本、CSV 等均可使用同样逻辑;如果是图片、视频等本身已压缩的文件,再次 gzip 收益极低,不建议二次压缩。

七、适用场景总结

✅ 适合:批量上报接口、大量JSON文本、日志上报、大数据同步
❌ 不适合:极小报文、图片/视频等已压缩媒体文件

当接口传输量大、网络带宽有限、跨机房调用时,开启请求体压缩能有效降低传输耗时,减少流量开销。

以上就是Python中HTTP请求体压缩的实现方法的详细内容,更多关于Python HTTP请求体压缩的资料请关注脚本之家其它相关文章!

相关文章

  • python 控制台单行刷新,多行刷新实例

    python 控制台单行刷新,多行刷新实例

    今天小编就为大家分享一篇python 控制台单行刷新,多行刷新实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • Python应用之利用pyecharts画中国地图

    Python应用之利用pyecharts画中国地图

    这篇文章主要介绍了Python应用之利用pyecharts画中国地图,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • Python实现发送与接收邮件的方法详解

    Python实现发送与接收邮件的方法详解

    这篇文章主要介绍了Python实现发送与接收邮件的方法,结合实例形式分析了Python基于smtplib库使用SMTP协议进行邮件发送及基于poplib库使用POP3服务器接收邮件的相关操作技巧,需要的朋友可以参考下
    2018-03-03
  • Python中的OpenCV图像阈值处理和平滑处理详解

    Python中的OpenCV图像阈值处理和平滑处理详解

    这篇文章主要介绍了Python中的OpenCV图像阈值处理和平滑处理详解,OpenCV是一个跨平台的计算机视觉库,可用于开发实时的图像处理、计算机视觉以及模式识别程序,需要的朋友可以参考下
    2023-08-08
  • python利用matplotlib库绘制饼图的方法示例

    python利用matplotlib库绘制饼图的方法示例

    Python强大的原因之一就在于其开源,有很多优秀的程序员为其提供了丰富的类库。Matplotlib就是其中之一,下面这篇文章主要介绍了python如何利用matplotlib库绘制饼图的方法示例,有需要的朋友们可以参考借鉴,下面来一起看看吧。
    2016-12-12
  • django中只使用ModleForm的表单验证

    django中只使用ModleForm的表单验证

    这篇文章主要介绍了django中只使用ModleForm的表单验证的相关资料,需要的朋友可以参考下
    2022-12-12
  • Python简单获取二维数组行列数的方法示例

    Python简单获取二维数组行列数的方法示例

    这篇文章主要介绍了Python简单获取二维数组行列数的方法,结合实例形式分析了Python基于numpy模块的二维数组相关运算技巧,需要的朋友可以参考下
    2018-12-12
  • django+tornado实现实时查看远程日志的方法

    django+tornado实现实时查看远程日志的方法

    今天小编就为大家分享一篇django+tornado实现实时查看远程日志的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • Python文件读写及常用文件的打开方式

    Python文件读写及常用文件的打开方式

    这篇文章主要介绍了Python文件读写及常用文件的打开方式,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • Python基础之函数嵌套知识总结

    Python基础之函数嵌套知识总结

    今天带大家回顾python基础知识,文中对Python函数嵌套作了非常详细的知识总结,对正在学习python基础的小伙伴们很有帮助,需要的朋友可以参考下
    2021-05-05

最新评论