Flask中正确读取request.data的XML数据需先校验Content-Type为application/xml,再用request.data.decode('utf-8')转字符串(前提前端统一UTF-8),并使用ET.XMLParser(resolve_entities=False)防XXE攻击后解析。

Flask中如何正确读取request.data里的XML原始数据
直接用 request.data 拿到的是 bytes,不是字符串,更不是已解析的XML对象。常见错误是没解码就传给 xml.etree.ElementTree.fromstring(),会报 TypeError: a bytes-like object is required, not 'str' 或编码错乱(比如中文变乱码)。
实操要点:
- 先检查
request.content_type是否为application/xml或text/xml,避免误处理非XML请求 -
request.data是原始字节流,需用request.data.decode('utf-8')转成字符串——但前提是客户端确实发的是UTF-8编码;若含,得按声明的编码解码(可用chardet探测,或让前端统一用UTF-8) - 解码后别直接丢给
ET.fromstring(),先用ET.XMLParser(resolve_entities=False)关闭外部实体解析,防XXE攻击
用xml.etree.ElementTree安全解析XML并提取字段
默认的 ET.fromstring() 会启用外部实体,如果客户端提交恶意XML(比如引用本地文件),可能读取服务器敏感文件。必须显式禁用。
示例代码片段:
from xml.etree import ElementTree as ET
from flask import Flask, request
<p>app = Flask(<strong>name</strong>)</p><p>@app.route('/api', methods=['POST'])
def handle_xml():
if not request.content_type.startswith('application/xml'):
return {'error': 'Content-Type must be application/xml'}, 400</p><pre class="brush:php;toolbar:false;">try:
# 禁用外部实体,防止XXE
parser = ET.XMLParser(resolve_entities=False)
root = ET.fromstring(request.data, parser=parser)
# 提取字段,例如 <user><name>Alice</name></user>
name_elem = root.find('name')
name = name_elem.text if name_elem is not None else None
return {'status': 'ok', 'name': name}
except ET.ParseError as e:
return {'error': f'Invalid XML: {str(e)}'}, 400
为什么不用request.get_data(as_text=True)?
看起来方便,但有坑:它默认用 utf-8 解码,且不校验XML声明中的 encoding 属性。如果客户端发的是 ,as_text=True 会硬解成UTF-8,导致解码失败或乱码。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
更稳妥的做法是自己控制解码逻辑:
- 先从
request.data提取前几百字节,用正则匹配encoding=["\']([^"\']+)["\']找声明编码 - 若没匹配到,再 fallback 到 UTF-8
- 用
request.data.decode(encoding)得字符串,再喂给ET.fromstring()
多数内部系统可强制约定前端发UTF-8 + 不带encoding声明,省去探测步骤。
遇到UnicodeDecodeError或中文乱码怎么办
根本原因:HTTP body 字节流和你用的解码方式不匹配。不是XML库的问题,是编码协商没对齐。
排查顺序:
- 用
print(repr(request.data[:50]))看原始字节,确认有没有b' 开头,以及中文是否已是乱码字节(如b'\xc4\xe3'表示 GBK 编码的“你”,而非UTF-8的b'\xe4\xbd\xa0') - 检查客户端发送时是否设置了
Content-Type: application/xml; charset=utf-8(注意分号后空格不影响,但 charset 必须明确) - 服务端不要依赖
request.charset—— Flask 默认不解析XML的charset参数,这个字段常为空,得靠request.content_type手动拆解
真正可靠的解法是前后端书面约定只用UTF-8,且XML声明里不写 encoding 属性(或统一写 encoding="UTF-8"),这样 request.data.decode('utf-8') 就稳了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










