需要做什麼?
如果使用get方法向伺服器發送如下資料:
name: zhangsan
from: beijing
content-type為application/x-www-form-urlencoded,則會傳輸資料:
name=zhangsan&from=beijing
可以看到兩組資料被&分割,這樣伺服器就能夠正确解析用戶端上傳的資料。那當使用post方法送出資料時,應該使用什麼樣的分割符呢? boundary
怎麼做?
- boundary不能與form表單的其他資料重複。
- boundary在整個請求中要保持一緻。
拼接如下表單:
—xxx—
Content-Disposition: form-data; name=”name”
zhangsan
—xxx—
Content-Disposition: form-data; name=”from”
beijing
—xxx—
Content-Disposition: file; name=”record”; filename=”record.txt”
Content-Type: text/plain
file upload blog.
代碼實作
# encoding: utf-8
# client.py
import itertools
import mimetools
import mimetypes
from cStringIO import StringIO
import urllib
import urllib2
class MultiPartForm():
def __init__(self):
self.form_fields = []
self.files = []
self.boundary = mimetools.choose_boundary()
def add_field(self, name, value):
"""添加field資料到form表單"""
self.form_fields.append((name, value))
def add_file(self, fieldname, filename, file_obj, mimetype=None):
"""添加檔案到表單"""
if not mimetype:
mimetype = mimetypes.guess_type(filename)[] or 'application/octet-stream'
self.files.append((fieldname, filename, mimetype, file_obj.read()))
def __str__(self):
"""拼接form封包"""
parts = []
part_boundary = "--%s" % self.boundary
# 添加fields
parts.extend(
[part_boundary,
'Content-Disposition: form-data; name="%s"' %name,
'',
value,] for name, value in self.form_fields
)
# 添加要上傳的files
parts.extend(
[part_boundary,
'Content-Disposition: file; name="%s"; filename="%s"' % (field_name, filename),
'Content-Type: %s' % content_type,
'',
body,] for field_name, filename, content_type, body in self.files
)
# 壓平parts添加boundary終止符
flattened = list(itertools.chain(*parts))
flattened.append('--%s--' % self.boundary)
flattened.append('')
return '\r\n'.join(flattened)
if __name__ == '__main__':
form = MultiPartForm()
form.add_field('name', 'zhangsan')
form.add_field('from', 'beijing')
form.add_file('record', 'record.txt', file_obj = StringIO('urllib2 file upload.'))
request = urllib2.Request('http://localhost:8080/')
body = str(form)
request.add_header('Content-type', 'multipart/form-data; boundary=%s' % form.boundary)
request.add_header('Content-length', len(body))
request.add_data(body)
print
print 'Request'
print request.get_data()
print
print 'Response'
print urllib2.urlopen(request).read()
# server.py
# framework 'web.py'
import web
urls = (
'/', 'hello'
)
app = web.application(urls, globals())
class hello:
def POST(self):
form = web.input()
return '\r\n'.join(['%s=%s' %(k,v) for k,v in form.items()])
if __name__ == "__main__":
app.run()
# result
python urllib2_upload_files.py
Request
--127.0.1.1.1000.31866.1426991278.082.1
Content-Disposition: form-data; name="name"
zhangsan
--127.0.1.1.1000.31866.1426991278.082.1
Content-Disposition: form-data; name="from"
beijing
--127.0.1.1.1000.31866.1426991278.082.1
Content-Disposition: file; name="record"; filename="record.txt"
Content-Type: text/plain
urllib2 file upload.
--127.0.1.1.1000.31866.1426991278.082.1--
Response
record=urllib2 file upload.
from=beijing
name=zhangsan