form-data类型
def multipart_producer(boundary, filename):
"""构建 multipart, 返回 yield, 实现分片上传"""
import time,chardet,os,mimetypes
def _encode(_str):
if not _str.strip():
return _str
if isinstance(_str, unicode):
return _str.encode('utf-8')
encoding = chardet.detect(_str).get('encoding') or 'utf-8'
# print _str, encoding
return _str.decode(encoding).encode('utf-8', 'ignore')
boundary_bytes = boundary.encode()
filename_bytes = _encode(filename)
start = time.time()
file_size = os.path.getsize(filename)
file_size_mb = round(float(file_size) / 1024 / 1024, 2)
mtype = mimetypes.guess_type(filename)[0] or "application/octet-stream"
buf = (
(b"--%s\r\n" % boundary_bytes)
+ (
b'Content-Disposition: form-data; name="file"; filename="%s"\r\n'
% (filename_bytes,)
)
+ (b"Content-Type: %s\r\n" % mtype.encode())
+ b"\r\n"
)
# print buf
yield buf
with open(filename, "rb") as f:
while True:
# 16k at a time.
chunk = f.read(160 * 1024)
# 打印上传进度
if time.time() - start > 5:
start = time.time()
print 'Total size: {} MB, Process {} %'.format(
file_size_mb,
round(float(f.tell()) / file_size * 100, 2)
)
if not chunk:
break
yield chunk
yield b"\r\n"
yield b"--%s--\r\n" % (boundary_bytes,)
使用方法
boundary = uuid4().hex
file_name = os.path.basename(path)
print '开始上传 {}'.format(file_name)
headers = {
'Content-Type': 'multipart/form-data; boundary={0}'.format(boundary), 'charset': 'UTF-8'}
data = multipart_producer(boundary, path)