使用Python requests复刻cURL multipart POST时遇415/400错误求助
问题分析与解决:requests复刻cURL multipart请求出错
问题背景
尝试用Python requests复刻指定cURL请求,已知不应手动设置"content-type": 'multipart/form-data'请求头,需由requests模块自动处理,但遇到两类错误:
- 不手动添加该请求头时,返回HTTP 415错误:
Unsupported media type - 手动添加该请求头时,返回HTTP 400错误:
Missing initial multi part boundary
原cURL命令
curl -X POST \ 'https://example.com/v1/endpoint' \ -H 'accept: application/json' \ -H 'Content-Type: multipart/form-data' \ -H 'Authorization: Bearer <BEARER_TOKEN_HERE>' \ -F 'name=test5' \ -F 'type=notebook' \ -F 'content=@some-file.json;type=application/json'
自行编写的Python代码
headers = { "accept": "application/json", "Authorization": "Bearer <BEARER_TOKEN_REDACTED>" } with open(path, mode="r") as f: data = f.read() stuff = { "name": "test1", "type": "notebook", "content": f"{data};type=application/json" } upload_resp = requests.post( url="https://example.com/endpoint", data=stuff, headers=headers ) return upload_resp
问题根源与修正方案
你存在三个关键错误:
- 请求参数使用错误:requests发送
multipart/form-data类型请求时,文件类字段必须通过files参数传递,而非data参数——data仅适用于普通表单编码(application/x-www-form-urlencoded)的请求。 - 文件字段构造错误:cURL中
@some-file.json;type=application/json的含义是上传指定文件并设置该字段的Content-Type,你直接拼接文件内容字符串的方式完全不符合multipart字段的格式要求。 - 请求路径不一致:你的代码中请求URL为
https://example.com/endpoint,但原cURL的路径是https://example.com/v1/endpoint,路径不匹配也可能导致接口识别失败。
修正后的代码示例
方案一:普通字段与文件字段分离传递
普通表单字段放在data参数,文件字段放在files参数:
import requests headers = { "accept": "application/json", "Authorization": "Bearer <BEARER_TOKEN_REDACTED>" } # 普通表单字段 form_fields = { "name": "test1", "type": "notebook" } # 文件字段采用元组格式:(文件名, 文件对象, 内容类型) with open(path, mode="rb") as f: upload_files = { "content": ("some-file.json", f, "application/json") } upload_resp = requests.post( url="https://example.com/v1/endpoint", data=form_fields, files=upload_files, headers=headers ) # 可根据需求处理响应 print(upload_resp.status_code) print(upload_resp.json())
方案二:所有字段统一放在files参数
若接口要求所有字段都在multipart表单中,可将普通字段也放入files,格式为(None, 字段值):
import requests headers = { "accept": "application/json", "Authorization": "Bearer <BEARER_TOKEN_REDACTED>" } with open(path, mode="rb") as f: multipart_fields = { "name": (None, "test1"), "type": (None, "notebook"), "content": ("some-file.json", f, "application/json") } upload_resp = requests.post( url="https://example.com/v1/endpoint", files=multipart_fields, headers=headers ) # 可根据需求处理响应 print(upload_resp.status_code) print(upload_resp.json())
额外注意事项
- 打开文件必须使用
rb(二进制只读)模式,避免文本编码导致文件内容损坏,确保和cURL上传的文件内容一致。 - 绝对不要手动添加
Content-Type: multipart/form-data请求头——requests会自动生成包含正确boundary的该头,手动添加会覆盖自动生成的boundary,导致接口无法解析请求,触发400错误。
内容的提问来源于stack exchange,提问作者A. Gardner
相关产品推荐
相关产品推荐

