在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()
|