
在使用 requests 向 Flask 服务发送 multipart/form-data 请求时,若手动设置 'Content-Type': 'multipart/form-data' 头,会导致 Flask 无法正确解析 request.form 和 request.files,所有数据被错误归入 request.data。根本原因是缺失 boundary 信息。
在使用 requests 向 flask 服务发送 multipart/form-data 请求时,若手动设置 `'content-type': 'multipart/form-data'` 头,会导致 flask 无法正确解析 `request.form` 和 `request.files`,所有数据被错误归入 `request.data`。根本原因是缺失 boundary 信息。
当你通过 Python 脚本调用 Flask 接口上传文件并提交表单字段(如 data_type、sample_rate)时,必须确保 HTTP 请求符合 multipart/form-data 的规范。该格式要求请求头中包含形如 multipart/form-data; boundary=----WebKitFormBoundaryxxx 的完整 Content-Type 字段,其中 boundary 是用于分隔各字段的唯一分界符。Flask(基于 Werkzeug)严格依赖此 boundary 解析请求体;若 boundary 缺失或不匹配,它将无法识别字段边界,从而跳过 form 和 files 的自动解析,仅将原始字节流存入 request.data。
问题根源在于手动覆盖了 requests 自动生成的 Content-Type 头。requests 库在检测到 files 参数时,会自动:
- 生成随机且唯一的 boundary;
- 构造完整的 Content-Type: multipart/form-data; boundary=... 头;
- 按照该 boundary 格式序列化 data 和 files 到请求体。
而一旦你显式传入 headers={'Content-Type': 'multipart/form-data'},就覆盖了 requests 原生生成的带 boundary 的头,导致服务器端失去解析依据。
✅ 正确做法:完全移除手动 headers
import requests
files = {
'file': open("path/to/your/file.bin", 'rb'),
}
data = {
'data_type': 'XYZ',
'sample_rate': '64',
}
# ✅ 正确:不传 headers,让 requests 自动处理
response = requests.post(
'http://127.0.0.1:8444/calculate',
files=files,
data=data
)⚠️ 错误示例(引发解析失败)
# ❌ 错误:手动指定不带 boundary 的 Content-Type
headers = {'Content-Type': 'multipart/form-data'}
response = requests.post(url, headers=headers, files=files, data=data) # → request.form 为空!? 验证技巧:检查 Flask 端请求对象
在 Flask 路由中添加调试日志,确认解析状态:
@app.route("/calculate", methods=['POST', 'OPTIONS'])
def calculate():
print("Headers:", dict(request.headers))
print("Form keys:", list(request.form.keys())) # 应输出 ['data_type', 'sample_rate']
print("Files keys:", list(request.files.keys())) # 应输出 ['file']
print("Raw data length:", len(request.data)) # 若非零且 form/files 为空,说明解析失败
process_data = request.form
uploaded_file = request.files.get('file')
data_type = process_data.get("data_type")
sample_rate = int(process_data.get("sample_rate")) # 注意:直接从 form 取值,无需额外 get()
# ... 后续逻辑? 补充注意事项
- 文件句柄需确保可读且未关闭;建议使用 with open(...) 或在 requests.post() 后及时 close();
- 若需自定义其他 header(如认证 token),可安全添加,但切勿覆盖 Content-Type;
- Postman/curl 默认正确生成 boundary,因此测试通过,这正反向印证了问题出在客户端 header 控制上;
- 对于大文件,考虑添加超时和流式上传支持(stream=True + 分块读取),但本例中非必需。
总结:信任 requests 的 multipart 自动化能力,避免手动干预 Content-Type 头——这是保障 Flask 正确解析表单与文件的黄金准则。










