问题描述
我正在尝试使用 Python requests 模块向我的 django rest 应用程序发送一些数据和文件,但出现以下错误.
raise MultiPartParserError('无效的多部分边界:%s' %边界)MultiPartParserError:多部分中的边界无效:无
代码:-
导入请求有效载荷 = {'管理员':[{'first_name':'约翰','last_name':'白','job_title':'CEO','email':'test1@gmail.com'},{'名字':'丽莎','last_name':'markel','job_title':'CEO','email':'test2@gmail.com'}],'company-detail':{'description':'我们是一家著名的工程公司','尺寸':'1-10','行业':'工程','url':'http://try.com','标识':'','addr1':'1280 灯芯','addr2':'1600','城市':'克维尔','state':'md','zip_cd':'12000','phone_number_1':'408-393-254','phone_number_2':'408-393-221','company_name':'GOOGLE'}}files = {'upload_file':open('./test.py','rb')}导入json标头 = {'内容类型':'应用程序/json'}headers = {'content-type':'multipart/form-data'}#r = requests.post('http://127.0.0.1:8080/api/create-company-profile/',data=json.dumps(payload),headers=headers,files=files)r = requests.post('http://127.0.0.1:8080/api/create-company-profile/',data=payload,headers=headers,files=files)打印 r.status_code打印 r.text
Django 代码:-
class CompanyCreateApiView(CreateAPIView):parser_classes = (MultiPartParser, FormParser,)def post(self, request, *args, **kwargs):打印 'request ==', request.data
好吧,我忘了你的标题.根据规范:
Content-Type = "Content-Type" ":" media-type
MIME 提供了许多多部分"类型——封装单个消息正文中的一个或多个实体.所有多部分类型共享一个通用语法,...并且必须包含一个边界参数作为媒体类型的一部分价值.
以下是包含 multipart/form-data 的请求的样子:
POST/myapp/company/HTTP/1.1主机:本地主机:8000内容长度:265接受编码:gzip、deflate接受: */*用户代理:python-requests/2.9.0连接:保持连接内容类型:多部分/表单数据;边界=63c5979328c44e2c869349443a94200e--63c5979328c44e2c869349443a94200e内容配置:表单数据;名称=你好"世界--63c5979328c44e2c869349443a94200e内容配置:表单数据;名称=我的数据";文件名=数据.txt"1号线2号线3号线4号线--63c5979328c44e2c869349443a94200e--
看看数据部分是如何被边界分隔的:
--63c5979328c44e2c869349443a94200e--
这个想法是使用一些不太可能出现在数据中的边界.请注意,边界包含在请求的 Content-Type
标头中.
该请求是由以下代码生成的:
导入请求myfile = {'mydata': open('data.txt','rb')}r = requests.post(网址,#headers = 我的标题数据 = {'你好':'世界'},文件 = 我的文件)
您似乎很注意 django-rest-framework 中的以下注释 文档:
注意:在开发客户端应用程序时,请始终记得确保您在 HTTP 中发送数据时设置 Content-Type 标头请求.
如果不设置内容类型,大多数客户端会默认使用'application/x-www-form-urlencoded',这可能不是您想要的.
但是当您使用 requests
时,如果您自己指定 Content-Type
标头,则 requests
假定您知道您的重新做,它不会用它提供的 Content-Type
标头覆盖您的 Content-Type
标头.
您没有按照要求在 Content-Type
标头中提供边界.你怎么能?您没有组装请求的正文并创建边界来分隔各种数据,因此您不可能知道边界是什么.
当 django-rest-framework
注释说您应该在请求中包含 Content-Type
标头时,这真正意味着:
您或您用于创建请求的任何程序都需要包含Content-Type
标头.
所以@AChampion 在评论中是完全正确的:让 requests
提供 Content-Type 标头
,毕竟 requests
文档做了广告:
Requests 完成了 Python HTTP/1.1 的所有工作
requests
的工作方式如下:如果您提供 files
关键字参数,则请求使用 multipart 的
并且还指定了标题中的边界;然后 Content-Type
标头/form-datarequests
使用边界组合请求的主体.如果您提供 data
关键字参数,则请求使用 application/x-www-form-urlencoded
的 Content-Type
,它只是组装所有字典中的键和值转换成这种格式:
x=10&y=20
不需要边界.
并且,如果您同时提供 files
关键字 arg 和 data
关键字 arg,则请求使用 Content-Type
的 >multipart/form-data
.
Im trying to send some data and file using Python requests module to my django rest application but get the below error.
raise MultiPartParserError('Invalid boundary in multipart: %s' % boundary)
MultiPartParserError: Invalid boundary in multipart: None
Code:-
import requests
payload={'admins':[
{'first_name':'john'
,'last_name':'white'
,'job_title':'CEO'
,'email':'test1@gmail.com'
},
{'first_name':'lisa'
,'last_name':'markel'
,'job_title':'CEO'
,'email':'test2@gmail.com'
}
],
'company-detail':{'description':'We are a renowned engineering company'
,'size':'1-10'
,'industry':'Engineering'
,'url':'http://try.com'
,'logo':''
,'addr1':'1280 wick ter'
,'addr2':'1600'
,'city':'rkville'
,'state':'md'
,'zip_cd':'12000'
,'phone_number_1':'408-393-254'
,'phone_number_2':'408-393-221'
,'company_name':'GOOGLE'}
}
files = {'upload_file':open('./test.py','rb')}
import json
headers = {'content-type' : 'application/json'}
headers = {'content-type' : 'multipart/form-data'}
#r = requests.post('http://127.0.0.1:8080/api/create-company-profile/',data=json.dumps(payload),headers=headers,files=files)
r = requests.post('http://127.0.0.1:8080/api/create-company-profile/',data=payload,headers=headers,files=files)
print r.status_code
print r.text
Django code:-
class CompanyCreateApiView(CreateAPIView):
parser_classes = (MultiPartParser, FormParser,)
def post(self, request, *args, **kwargs):
print 'request ==', request.data
Okay, I forgot about your headers. According to the spec:
Here is what a request containing multipart/form-data looks like:
POST /myapp/company/ HTTP/1.1
Host: localhost:8000
Content-Length: 265
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: python-requests/2.9.0
Connection: keep-alive
Content-Type: multipart/form-data; boundary=63c5979328c44e2c869349443a94200e
--63c5979328c44e2c869349443a94200e
Content-Disposition: form-data; name="hello"
world
--63c5979328c44e2c869349443a94200e
Content-Disposition: form-data; name="mydata"; filename="data.txt"
line 1
line 2
line 3
line 4
--63c5979328c44e2c869349443a94200e--
See how the sections of data are separated by the boundary:
--63c5979328c44e2c869349443a94200e--
The idea is to use something for a boundary that is unlikely to appear in the data. Note that the boundary was included in the Content-Type
header of the request.
That request was produced by this code:
import requests
myfile = {'mydata': open('data.txt','rb')}
r = requests.post(url,
#headers = myheaders
data = {'hello': 'world'},
files = myfile
)
It looks like you were paying careful attention to the following note in the django-rest-framework docs:
But when you are using requests
, if you specify the Content-Type
header yourself, then requests
assumes that you know what you're doing, and it doesn't overwrite your Content-Type
header with the Content-Type
header it would have provided.
You didn't provide the boundary in your Content-Type
header--as required. How could you? You didn't assemble the body of the request and create a boundary to separate the various pieces of data, so you couldn't possibly know what the boundary is.
When the django-rest-framework
note says that you should include a Content-Type
header in your request, what that really means is:
So @AChampion was exactly right in the comments: let requests
provide the Content-Type header
, after all the requests
docs advertise:
requests
works like this: if you provide a files
keyword arg, then requests uses a Content-Type
header of multipart/form-data
and also specifies a boundary in the header; then requests
assembles the body of the request using the boundary. If you provide a data
keyword argument then requests uses a Content-Type
of application/x-www-form-urlencoded
, which just assembles all the keys and values in the dictionary into this format:
x=10&y=20
No boundary required.
And, if you provide both a files
keyword arg and a data
keyword arg, then requests uses a Content-Type
of multipart/form-data
.
这篇关于MultiPartParserError :- 边界无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!