上传文件是以multipart/form-data的方式将文件内容POST到服务器端,python的HTTP通信库(urllib、urllib2之类)默认不支持multipart协议,但可以按协议格式自行实现:
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)[0] 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__':
filename = './images/a.jpg'
form = MultiPartForm()
form.add_file('image', 'a.jpg', file_obj = open(filename))
request = urllib2.Request('http://url.com/s/api?cmd=Image.add')
body = str(form)
request.add_header('Content-type', 'multipart/form-data; boundary=%s' % form.boundary)
request.add_header('Content-length', len(body))
request.add_header('Cookie', 'SPSSID=xxxxxxxxxx')
request.add_data(body)
print(urllib2.urlopen(request).read())
wget当前不支持multipart,不过,也可以采用添加multipart头,并手动修改上传文件的方式实现。mutlipart头例如:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryR5xMWIPvfrpzmD5S
wget的--post-file参数并不是指定要上传的文件,而是指定存有query串的文本,也就是说你可以--post-data "name=abc&age=100",也可以将"name=abc&age=100"存在文件tmp.txt里,然后--post-file "tmp.txt"。所以将要编辑要上传的二进制文件成如下格式:
------WebKitFormBoundaryR5xMWIPvfrpzmD5S
Content-Disposition: form-data; name="image"; filename="a.jpg"
Content-Type: image/jpeg
[二进制文件内容]
------WebKitFormBoundaryR5xMWIPvfrpzmD5S
Content-Disposition: form-data; name="cmd"
Image.add
------WebKitFormBoundaryR5xMWIPvfrpzmD5S--
特别注意:此处的回车换行必须依据HTTP规定,使用"\r\n"。
curl直接就支持了multipart,使用起来就是一个参数而已,非常方便:
curl -X POST -b "SESSIONID=xxxxx" -F "image=@a.jpg" "http://example.com/s/api?cmd=Image.add"
如果不上传文件,只是普通post提交数据,命令举例如下:
curl -X POST -b "SESSONID=xxxxx" -d "cmd=Archive.del&userId=101&archiveId=100" "http://example.com/s/api"
POST内容来自于文件:
curl -X POST 'http://example.com/update/' -d @data.json