如何用Python Requests正确提交multipart/form-data类型表单?
问题场景
我要提交的表单代码如下:
<form method="post" action="deliverData.php" enctype="multipart/form-data"> <p><input type="checkbox" name="Description" value="Yes"> Include Course Description <p><input type="checkbox" name="Extended" value="Yes"> Include Additional Class Meetings ... <input type="hidden" name="Group" value="Mathematics" /> </form>
浏览器里看到的POST请求负载是这样的:
------WebKitFormBoundaryNfRaBsIDJ61noG2M Content-Disposition: form-data; name="Description" Yes ------WebKitFormBoundaryNfRaBsIDJ61noG2M Content-Disposition: form-data; name="Extended" Yes ------WebKitFormBoundaryNfRaBsIDJ61noG2M ...
用手动拼接payload+指定Content-Type的代码能成功拿到响应:
headers = {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryNfRaBsIDJ61noG2M"} data = ''' <上面复制的payload内容> ''' response = requests.post(base_url, headers=headers, data=data)
但换成字典传参就报服务器500错误:
json1 = { 'Description': 'Yes', 'Extended': 'Yes', 'InstructionMode': 'Yes', ...} response = requests.post(base_url, headers=headers, data=json1)
虽然能用f-string改payload参数,但这显然不是规范用法,想知道正确的提交方式是什么?
解决方案
问题根源是你手动指定了Content-Type头,同时用字典传递data参数,导致请求体编码格式和请求头不匹配,服务器解析失败。
Requests库本身会自动处理multipart/form-data的编码流程,包括生成合法的boundary、组装请求头和请求体,完全不需要你手动干预。正确的做法分两种情况:
1. 无文件上传的multipart表单提交
如果只是提交普通表单字段(没有文件上传),但要求用multipart/form-data编码,把表单字段放到files参数里,每个字段值用(None, 字段值)的元组格式:
# 定义所有表单字段 form_data = { 'Description': 'Yes', 'Extended': 'Yes', 'Group': 'Mathematics', # 其他需要提交的字段... } # 转换为multipart格式要求的结构 multipart_payload = {key: (None, value) for key, value in form_data.items()} # 直接提交,无需手动设置Content-Type response = requests.post(base_url, files=multipart_payload)
2. 带文件上传的情况(如果后续需要)
如果表单包含文件上传字段,直接把文件路径/对象放到files参数对应的键里即可,普通字段依然用data传递,Requests会自动合并为multipart格式:
form_data = { 'Description': 'Yes', 'Extended': 'Yes' } files = { 'upload_file': open('file.txt', 'rb') } response = requests.post(base_url, data=form_data, files=files)
为什么之前的字典方式失败?
当你手动设置Content-Type: multipart/form-data头时,Requests用data字典传参的默认编码格式是application/x-www-form-urlencoded,这就导致请求头声明的格式和实际请求体的编码格式不匹配,服务器无法正确解析,所以返回500错误。
另外,手动拼接multipart payload的方式不仅维护麻烦,还容易因为换行、boundary拼写错误等导致请求失败,完全不推荐。让Requests自动处理编码才是规范的做法。
内容的提问来源于stack exchange,提问作者sogaj53

