-
Notifications
You must be signed in to change notification settings - Fork 236
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Reqable Bug Report: GBK 编码响应头解析错误
问题描述
Reqable 在处理包含中文 GBK 编码的 HTTP 响应头(特别是 Content-Disposition 头)时,存在字符编码解析错误,导致中文文件名显示为乱码或问号。
问题复现
测试环境
- 目标域名:
xx.com.cn(隐私) - 文件类型: PDF 研报下载
- 问题场景: 服务端返回的
Content-Disposition响应头包含 GBK 编码的中文文件名
实际案例
案例 1
服务端发送的响应头(推测,基于常见服务端实现):
Content-Disposition: attachment; filename="20260205-华泰证券-2026年游戏行业发展展望.pdf"
其中 "华泰证券" 等中文以 GBK 编码存储在 HTTP 头中。
Reqable 解析后的结果(在插件中通过 response.headers['content-disposition'] 获取):
attachment; filename="20260205-????֤ȯ-2026??Ϸ??ҵ????չ??????to B??to C??AI??Ϸ???濪ʼ????ƽ̨????.pdf"
字节级分析:
# 部分字符的码点值(通过 ord() 获取)
'?' → 0x3f # 问号(解码失败标志)
'֤' → 0x5a4 # 应该是两个 GBK 字节被错误合并
'ȯ' → 0x22f # 应该是两个 GBK 字节被错误合并
'Ϸ' → 0x3f7 # 应该是两个 GBK 字节被错误合并从字节码可以看出,Reqable 将 GBK 双字节序列错误地解析成了 Unicode 字符。
案例 2
Raw: 'attachment; filename="20260201-??????-??۾??ú?ծȯ?г?һ?ܹ۵㣺????????ծ????519ֻ??.pdf"'
字节码: [..., '0x6fe', '0x56e', '0x22f', '0x433', '0x79', '0x68', ...]
包含大量问号 ? 和超过 0xFF 的 Unicode 字符(如 0x6fe, 0x56e),说明解码彻底失败。
问题根因分析
HTTP 协议规范
根据 RFC 2616 和 RFC 5987:
- HTTP 响应头默认应使用 ISO-8859-1 (Latin-1) 编码
- 对于非 ASCII 字符(如中文),应使用 RFC 2231/5987 扩展格式:
Content-Disposition: attachment; filename*=UTF-8''%E4%B8%AD%E6%96%87.pdf - 或者使用百分号编码
服务端实现问题
xx.com.cn 服务端没有遵循 RFC 规范,而是:
- 直接将 GBK 编码的字节流放入
filename="..."中 - 没有使用
filename*=扩展格式 - 没有进行百分号编码
虽然服务端不规范,但许多 HTTP 客户端(如浏览器)能够正确处理这种情况,因为它们会:
- 尝试检测非 ASCII 字节
- 根据系统或响应内容推测编码(GBK/GB18030/UTF-8)
- 自动转码为正确的 Unicode
Reqable 的问题
Reqable 在解析响应头时,似乎使用了固定的 UTF-8 解码或其他不兼容 GBK 的方式,导致:
- 问号
?大量出现: GBK 单字节无法用 UTF-8 解码时被替换为? - 高位 Unicode 字符: GBK 双字节
(B1, B2)被错误地合并为一个 Unicode 码点(B1 << 8 | B2)- 例如: GBK
0xBB 0xAA("华") → 被解析为 UnicodeU+BBAA(一个无效字符)
- 例如: GBK
实际字节流对比:
| 正确的GBK字节 | Reqable解析结果 | 说明 |
|---|---|---|
0xBB 0xAA ("华") |
U+05A4 或 ? |
错误合并或解码失败 |
0xCC 0xA9 ("泰") |
U+052A 或 ? |
错误合并或解码失败 |
0xD6 0xA4 ("证") |
U+05A4 |
错误合并 |
0xC8 0xAF ("券") |
U+022F |
错误合并 |
影响范围
- 中国大陆的企业级服务: 许多老旧系统仍使用 GBK 编码
- 金融、政务、学术机构: 研报、文档下载场景普遍存在
- 用户体验: 下载的文件名显示为乱码,无法识别文件内容
复现步骤
- 启动 Reqable 并启用抓包
- 访问
https://xxx.com.cn(需要登录) - 下载任意中文名称的 PDF 研报
- 观察响应头中的
Content-Disposition字段 - 在插件脚本中通过
response.headers['content-disposition']获取,会发现中文乱码
期望行为
Reqable 应该:
方案 1: 智能编码检测(推荐)
- 在解析响应头时,检测是否包含非 ASCII 字节(
>= 0x80) - 尝试按以下优先级解码:
- UTF-8
- GBK / GB18030(针对中国用户)
- Big5(针对繁体中文)
- ISO-8859-1(后备)
- 选择解码成功且包含有效字符最多的结果
方案 2: 用户配置
- 在 Reqable 设置中添加"响应头编码"选项
- 允许用户手动选择:
UTF-8/GBK/GB18030/ISO-8859-1/Auto
方案 3: 保留原始字节
- 在插件 API 中提供访问原始字节的接口:
# 新增 API raw_bytes = response.headers.get_raw_bytes('content-disposition') # 插件自行解码 decoded = raw_bytes.decode('gbk', errors='ignore')
临时解决方案(脚本层面)
由于 Reqable 已经做了错误的字符串解码,插件脚本无法获取原始字节,导致无法在脚本层面完美修复此问题。
我们尝试了以下方法但均失败:
- ✗
latin-1 → GBK转码(原始字节已丢失) - ✗ 拆分高位 Unicode 字符(拆分后的字节无法正确重组为 GBK)
- ✗ 遍历多种编码尝试解码(所有方案都产生大量问号和乱码)
优先级
高优先级 - 影响中国用户日常使用,特别是企业用户和开发者。
相关标准
- RFC 2616 - HTTP/1.1
- RFC 5987 - 字符集和语言编码用于超文本传输协议(HTTP)头字段参数
- RFC 6266 - 在超文本传输协议(HTTP)中使用Content-Disposition头字段
测试用例
建议添加以下测试用例:
# 测试用例 1: GBK 编码的中文文件名
assert parse_header('attachment; filename="测试文件.pdf"', encoding='gbk') == '测试文件.pdf'
# 测试用例 2: UTF-8 编码的中文文件名
assert parse_header('attachment; filename="测试文件.pdf"', encoding='utf-8') == '测试文件.pdf'
# 测试用例 3: RFC 5987 标准格式
assert parse_header('attachment; filename*=UTF-8\'\'%E6%B5%8B%E8%AF%95.pdf') == '测试.pdf'
# 测试用例 4: 混合编码(服务端非标准实现)
assert parse_header('attachment; filename="20260205-华泰证券-报告.pdf"', encoding='gbk') == '20260205-华泰证券-报告.pdf'联系信息
如需更多信息或测试样本,请联系:
- 用户反馈渠道: icremankozleesah@gmail.com
- 测试环境: Windows 11, Reqable 3.0.38
附录: 调试日志示例
[DEBUG] Raw Content-Disposition: 'attachment; filename="20260205-????֤ȯ-2026年游戏行业发展展望.pdf"'
[DEBUG] Content-Disposition bytes: ['0x3f', '0x3f', '0x3f', '0x3f', '0x5a4', '0x22f', ...]
[DEBUG] 字符 '֤' (U+05A4) 应该对应 GBK 字节 0xD6 0xA4 ("证")
[DEBUG] 字符 'ȯ' (U+022F) 应该对应 GBK 字节 0xC8 0xAF ("券")
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
