curl、Postman可正常上传文件,Python requests调用API失败
我太懂这种抓瞎的感觉了——curl和Postman都能正常传文件,偏偏用requests就卡壳,API还没什么错误提示,简直挠头!结合你的环境(Python3.5、requests2.18.4、OSX10.11.6),我给你几个亲测有效的排查和解决方向:
1. 严格复刻curl的请求结构
curl的-F 'file=@/path/to/file.csv'本质是发送multipart/form-data请求,其中file是表单字段名,对应文件内容。requests里必须用files参数实现,别把文件塞到data里!
直接用这段代码试试,完全对齐curl的逻辑:
import requests # 替换成你的实际URL和token url = 'https://myurl.com/upload' headers = {'Authorization': 'TOKEN sometoken'} # 必须用二进制模式打开文件,这是关键! with open('/path/to/file.csv', 'rb') as f: files = {'file': f} response = requests.post(url, headers=headers, files=files) # 哪怕错误信息少,也先把响应内容打出来找线索 print(f"状态码: {response.status_code}") print(f"响应内容: {response.text}")
2. 显式指定文件名和MIME类型
有些API会校验表单里的文件名或文件类型,curl会自动从路径提取文件名,但requests偶尔会处理不到位。你可以显式指定:
with open('/path/to/file.csv', 'rb') as f: # 格式是 (文件名, 文件对象, MIME类型) files = {'file': ('file.csv', f, 'text/csv')} response = requests.post(url, headers=headers, files=files)
3. 别手动加Content-Type头!
这是很多人踩的坑:手动在headers里加Content-Type: multipart/form-data。但requests会自动生成这个头,还会加上必要的boundary分隔符——手动加的话会丢失boundary,导致API根本解析不了请求。
一定要删掉headers里的Content-Type字段,让requests自动处理!
4. 对比curl和requests的请求差异
如果上面的方法都不行,就抓包看两个请求的区别。你可以用requests的debug日志查看实际发送的请求内容:
import logging import http.client import requests # 开启debug日志,会输出完整请求细节 http.client.HTTPConnection.debuglevel = 1 logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) requests_log = logging.getLogger("requests.packages.urllib3") requests_log.setLevel(logging.DEBUG) requests_log.propagate = True # 再发送一次请求,控制台会打印完整请求头和内容 url = 'https://myurl.com/upload' headers = {'Authorization': 'TOKEN sometoken'} with open('/path/to/file.csv', 'rb') as f: files = {'file': f} response = requests.post(url, headers=headers, files=files)
把这个日志和curl -v ...输出的请求对比,重点看:
Authorization头是否完全一致(注意TOKEN后面的空格!)multipart/form-data的boundary是否正确生成- 文件内容的传输是否完整
5. 尝试升级requests版本
你的requests是2.18.4,虽然基本功能没问题,但旧版本可能有multipart上传的小bug。Python3.5最高支持requests2.26.0,你可以用pip升级试试:
pip install requests==2.26.0
我之前就是因为手动加了Content-Type头卡了半天,去掉就立马好了😂 按这个步骤来,大概率能解决问题!
内容的提问来源于stack exchange,提问作者dukeluke

