
当系统中安装了 zstandard 第三方库时,Requests 会自动在 Accept-Encoding 请求头中加入 zstd,导致服务器返回 zstd 压缩内容但 Requests 默认不处理解压,引发乱码;卸载 zstandard 即可全局禁用该行为。
当系统中安装了 `zstandard` 第三方库时,requests 会自动在 `accept-encoding` 请求头中加入 `zstd`,导致服务器返回 zstd 压缩内容但 requests 默认不处理解压,引发乱码;卸载 `zstandard` 即可全局禁用该行为。
在 Python 生态中,requests 库本身不原生支持 zstd 解压缩——它仅负责发送请求并接收原始响应体。但自 requests v2.31.0(2023年发布)起,其内部引入了一项隐式兼容机制:若检测到已安装第三方压缩库 zstandard(即通过 import zstandard 成功),则会自动将 zstd 添加至默认 Accept-Encoding 头中,形如:
Accept-Encoding: gzip, deflate, br, zstd
这一设计初衷是“按需协商最优压缩”,但带来一个关键矛盾:Requests 不会自动解压 zstd 编码的响应体( unlike gzip 或 deflate,后者由标准库 gzip/zlib 支持且 requests 内置解压逻辑)。结果就是:响应 .content 返回的是未经解压的二进制 zstd 流(如你看到的 \xb5/\xfd\x04X...),直接使用将导致解析失败、乱码或后续处理崩溃。
✅ 根本原因确认方法:
运行以下代码即可验证是否受此影响:
import requests
print("zstandard available:", True if requests.packages.urllib3.util.ssl_.HAS_ZSTD else False)
# 或更直接地:
try:
import zstandard
print("zstandard is installed → requests will advertise 'zstd' encoding")
except ImportError:
print("zstandard not found → no zstd in Accept-Encoding")
? 推荐解决方案(优先级从高到低):
-
✅ 卸载
zstandard(最简洁、全局生效)pip uninstall zstandard
✅ 优点:一劳永逸,所有
requests.get()/.post()自动回归传统gzip, deflate, br协商,无须修改任何业务代码。
⚠️ 注意:仅当你不需要在其他地方主动使用 zstd 压缩/解压功能时适用。若项目依赖zstandard进行本地数据压缩,请跳至方案 2 或 3。 -
✅ 全局禁用 zstd 协商(保留 zstandard 库)
在程序启动早期(import requests后、首次发起请求前)执行:import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 强制移除 zstd —— 修改 requests 的默认编码列表 requests.utils.default_user_agent = lambda: "python-requests/2.31.0" # 更可靠的方式: monkey patch urllib3 的编码检测逻辑 try: import urllib3 urllib3.util.ssl_.HAS_ZSTD = False # 关键!欺骗 urllib3 认为 zstd 不可用 except ImportError: pass此后所有请求将不再携带
zstd。 -
⚠️ 逐请求控制(灵活性高,但需代码改造)
显式覆盖Accept-Encoding,排除zstd:headers = {"Accept-Encoding": "gzip, deflate, br"} # 明确指定,不含 zstd response = requests.get("https://example.com", headers=headers)
? 重要补充说明:
- Python 3.14(2025年10月发布)已将
compression.zstd纳入标准库,但requests尚未适配该新模块;当前所有 zstd 行为均源于第三方zstandard库的检测逻辑。 - 若你使用的是 Synology DSM 7 系统,其 Python 环境常预装
zstandard(用于日志或备份模块),故升级后脚本突然异常属典型场景。 - 切勿使用
verify=False或stream=True等无关参数试图“绕过”——问题本质是编码协商与解压能力不匹配,而非 SSL 或流控。
? 总结:zstandard 是“开关”,不是“解压器”。卸载它是最符合 Python “显式优于隐式”哲学的解决路径。保持环境纯净,让 requests 回归其稳健、可预测的默认行为。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











