在Python中,我们通常使用urllib2中提供的工具来完成HTTP请求,例如向服务器POST数据。通常情况下,所有的数据都会进行URL编码并将Content-Type设置为application/x-www-form-urlencoded。不过在一些特殊的情况下(例如服务器限制而不允许使用这种类型的数据提交)或者上传文件的时候,则需要用到multipart/form-data格式的POST提交。
这种时候,我们可以手动对数据进行封装,如下面的代码所做的操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
def
encode_multipart_formdata(fields, files):
"""
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files
Return (content_type, body) ready for httplib.HTTP instance
"""
BOUNDARY
=
mimetools.choose_boundary()
CRLF
=
'\r\n'
L
=
[]
for
(key, value)
in
fields:
L.append(
'--'
+
BOUNDARY)
L.append(
'Content-Disposition: form-data; name="%s"'
%
key)
L.append('')
L.append(value)
for
(key, filename, value)
in
files:
L.append(
'--'
+
BOUNDARY)
L.append(
'Content-Disposition: form-data; name="%s"; filename="%s"'
%
(key, filename))
L.append(
'Content-Type: %s'
%
get_content_type(filename))
L.append('')
L.append(value)
L.append(
'--'
+
BOUNDARY
+
'--'
)
L.append('')
body
=
CRLF.join(L)
content_type
=
'multipart/form-data; boundary=%s'
%
BOUNDARY
return
content_type, body
def
get_content_type(filename):
return
mimetypes.guess_type(filename)[
0
]
or
'application/octet-stream'
|
encode_multipart_formdata()方法是这里的主角,它将所有POST数据进行封装并返回content_type和POST数据实体(body)的元组。
有了上面的函数,我们接下来就再借助于HTTPConnection来完成整个请求过程:
1
2
3
4
5
6
7
8
9
|
def
post_data(host, path, fields, files):
content_type, body
=
encode_multipart_formdata(fields, files)
client
=
httplib.HTTPConnection(host, port)
headers
=
{
'content-type'
: content_type}
client.request(
'POST'
, path, body, headers)
response
=
client.getresponse()
return
response.read()
|