Python requests实现远程URL文件上传API的解决方案
问题排查
你写的代码跑不通是两个低级错误:
- 连续调用了两次
requests.post发上传请求,第一次发的时候已经把r.raw的响应流读完了,第二次发请求的时候流指针已经在末尾,读出来是空内容,自然上传失败 - 直接把
r.raw传给files参数时,requests不会自动正确处理分块传输、gzip压缩的响应流,很容易出现内容截断、编码错误的问题,而且你没加任何异常判断,远程文件拉取失败的时候代码还会继续往下跑,传一堆无效数据。
可直接运行的实现方案
分两种场景选就行:
场景1:文件体积不大(100MB以内)
最稳定的写法,不需要存本地磁盘,直接把远程文件内容读进内存上传,不需要额外依赖:
import requests # 替换成你自己的参数 upload_api = "https://api.app.com/api/1/profile/1234/verification/44" remote_file_url = "https://secure-data.company.com?k=i1jdXN0b21lci1rZXktbWQ1PU5DNCUyRjNTand4TllrUGpNSFc3SmVtUSUzRCUzRCZYLUFtei1" auth_headers = { "Accept": "application/json", "Authorization": "Bearer blah:blah" } # 拉取远程文件 file_resp = requests.get(remote_file_url, timeout=30) file_resp.raise_for_status() # 拉取失败(比如链接过期、403)直接抛错,不往下走 # 构造上传参数,直接传二进制内容,文件名和MIME类型和实际文件匹配即可 upload_files = { "file": ("licence.jpg", file_resp.content, "image/jpeg") } result = requests.post(upload_api, headers=auth_headers, files=upload_files, timeout=60) print(result.text)
场景2:大文件上传(100MB以上)
为了避免把整个文件读进内存占满资源,用流式上传的写法,需要先装依赖:pip install requests-toolbelt
import requests from requests_toolbelt import MultipartEncoder # 替换成你自己的参数 upload_api = "https://api.app.com/api/1/profile/1234/verification/44" remote_file_url = "https://secure-data.company.com?k=i1jdXN0b21lci1rZXktbWQ1PU5DNCUyRjNTand4TllrUGpNSFc3SmVtUSUzRCUzRCZYLUFtei1" auth_headers = { "Accept": "application/json", "Authorization": "Bearer blah:blah" } # 流式拉取远程文件,不一次性读全量内容 file_resp = requests.get(remote_file_url, stream=True, timeout=30) file_resp.raise_for_status() file_resp.raw.decode_content = True # 自动处理gzip等压缩格式 # 构造流式分块上传器 multipart_encoder = MultipartEncoder( fields={ "file": ("licence.jpg", file_resp.raw, "image/jpeg") } ) # 追加上传需要的Content-Type头,必须用编码器自动生成的带边界值的头,不能手动写死 upload_headers = auth_headers.copy() upload_headers["Content-Type"] = multipart_encoder.content_type result = requests.post(upload_api, headers=upload_headers, data=multipart_encoder, timeout=120) print(result.text)
避坑提醒
- 所有网络请求一定要加
timeout参数,不然遇到网络波动会直接把程序卡死 - 流对象只能读一次,不要重复用同一个流对象发多次请求
- 上传时的文件名、MIME类型要和实际文件匹配,比如png文件就对应
image/png,pdf就对应application/pdf,写错了可能被目标接口判定为无效文件 - 拉取远程文件后一定要校验状态,不要等链接过期返回403错误页了还往上传接口送
内容的提问来源于stack exchange,提问作者Brett
相关产品推荐
相关产品推荐

