在Flask里处理XML格式的请求数据,不少人拿到`request.data`就直接往解析函数里丢,结果要么报`TypeError`,要么中文变乱码。其实核心问题就几个:编码没对齐、外部实体没关、Content-Type没校验。下面把这些坑一个个填平,顺便给出一套能直接上生产环境的做法。

### 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`,避免把JSON或表单数据当成XML处理。
- `request.data`是原始字节,需要用`request.data.decode('utf-8')`转成字符串——前提是客户端确实用的UTF-8编码。如果XML声明里写的是``,就得按声明编码解码(可以用`chardet`探测,或者直接约定前端统一用UTF-8)。
- 解码后别直接丢给`ET.fromstring()`,先用`ET.XMLParser(resolve_entities=False)`关闭外部实体解析,这是防XXE攻击的标准做法。
### 用`xml.etree.ElementTree`安全解析XML并提取字段
默认的`ET.fromstring()`会启用外部实体解析,如果客户端提交恶意XML(比如引用本地文件路径),可能读取
服务器敏感文件。必须显式禁用。
下面是一段可直接复用的示例代码:
```python
from xml.etree import ElementTree as ET
from flask import Flask, request
app = Flask(__name__)
@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
try:
# 禁用外部实体,防止XXE
parser = ET.XMLParser(resolve_entities=False)
root = ET.fromstring(request.data, parser=parser)
# 提取字段,例如
Alice
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解码,结果就是乱码或解码失败。
更稳妥的做法是自己控制解码逻辑:
- 先从`request.data`里取出前几百字节,用正则匹配`encoding=["\']([^"\']+)["\']`找到声明编码。
- 如果没有匹配到,回退到UTF-8。
- 用`request.data.decode(encoding)`得到字符串,再喂给`ET.fromstring()`。
对于内部系统,最省事的办法是强制约定前端只发UTF-8且不写encoding声明,这样`request.data.decode('utf-8')`就稳稳当当。
### 遇到`UnicodeDecodeError`或中文乱码怎么办
根本原因只有一个:HTTP body的字节流和解码方式不匹配。这锅不该甩给XML库,而是编码协商没对齐。
排查顺序:
- 先用`print(repr(request.data[:50]))`看看原始字节。确认开头是不是`b'
本文转载于:https://www.php.cn/faq/2426636.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。