XML文件压缩上传 Gzip压缩XML请求体的实现

1次阅读

http请求头必须显式声明content-encoding: gzip,服务端不会自动识别gzip压缩;xml需先utf-8编码再压缩,且服务端须配置解压支持,否则报错。

XML文件压缩上传 Gzip压缩XML请求体的实现

HTTP 请求头必须显式声明 Content-Encoding: gzip

服务端不会自动识别请求体是否被 gzip 压缩,不加这个头,后端大概率直接解析原始字节流,报 XML parse ErrorUnexpected Token x1f(gzip 魔数)。常见于用 curlpostman 手动构造时漏掉。

  • Python requests:需手动设置 headers={'Content-Encoding': 'gzip'},不能依赖 requests.post(..., data=gzipped_bytes) 自动推断
  • Java HttpURLConnection:调用 conn.setRequestProperty("Content-Encoding", "gzip"),且必须在 setDoOutput(true) 之后、getOutputStream() 之前
  • Node.js fetch:同理,headers: { 'Content-Encoding': 'gzip' } 是硬性要求,否则 express/Koa 中间件收不到压缩信号

XML 字符串必须先转为 UTF-8 字节再压缩,不能压缩字符串对象

很多开发者误以为对 XML 字符串调用 gzip.compress(xml_str) 就行,但 Python 的 gzip、Node 的 zlib.gzipSync接口只接受 bytes(或 Uint8Array),传入字符串会隐式编码成系统默认编码(如 windows 上是 cp1252),导致解压后乱码或解析失败。

  • Python 正确写法:gzipped = gzip.compress(xml_str.encode('utf-8'))
  • Node.js 正确写法:const gzipped = zlib.gzipSync(Buffer.from(xml_str, 'utf-8'))
  • Java 注意:String.getBytes(StandardCharsets.UTF_8),别用无参 getBytes()

服务端未配置 gzip 解压时,Content-Encoding: gzip 会被忽略或报 415

不是所有后端框架默认解压请求体。spring Boot 2.3+ 默认不处理 gzip 请求体;Express 默认也不解压;nginx 作为反向代理时,若没配 gzip_disable "msie6";client_max_body_size,可能直接拒收或截断。

  • spring boot:需加 @Bean 注册 RequestBodyAdvice 或启用 server.compression.enabled=true(仅对响应有效,请求仍需手动解压)
  • Express:必须用 express.raw({ type: 'application/xml', limit: '5mb' }) 接收原始二进制,再用 zlib.unzipSync() 解压
  • Nginx:确认 gzip on;gzip_http_version 1.1; 已设,否则可能丢弃 Content-Encoding

压缩前检查 XML 是否已含 bom 或非法控制字符

带 BOM 的 UTF-8 XML(即开头三个字节 xefxbbxbf)压缩后,部分老版本 Java SAX 解析器会把 BOM 当作非法字符报错;而某些 XML 库(如 .NET XmlDocument.Load())对压缩后残留的 x00x01 等控制字符更敏感。

  • Python 发送前可清理:xml_str = xml_str.replace('ufeff', '').strip()(移除 BOM)
  • 建议在压缩前用 xml.etree.ElementTree.fromstring(xml_str) 预校验合法性,比让服务端报错更早发现问题
  • 避免用 lxmltostring(..., encoding='utf-8', xml_declaration=True) 输出带 BOM 的内容

事情说清了就结束。最常卡住的地方不是压缩本身,而是服务端没开解压、或者客户端把字符串当字节压了——这两个点一错,错误信息看起来完全不相关。

text=ZqhQzanResources