python发送文件_解决python发送multipart/form-data请求上传文件的问题

服务器接收文件时,有时会使用表单接收的方式,这意味着我们需要使用Python的requests上传表单数据和文件。

常用的方式一般如下:

data = {

‘name‘: ‘nginx‘

}

files = {‘file‘: open("abc.csv", ‘rb‘)}

response = requests.post(url, data=data, files=files)

files是封装好的参数,直接包括了文件内容,文件名,格式等,data则是表单内容,但这样做有一个问题,文件是中文名时,requests就会报错,哪怕encode转码成utf8也没用

百度发现除了requests的这个方法,还可以用一个第三方包MultipartEncoder,而这个包相对来说比较灵活。

一般是from requests_toolbelt.multipart.encoder import MultipartEncoder,这样导入使用

由于公司项目需要兼容各种环境,不主张使用大量第三方库,我精简模块后提取出my_compat 文件,变成 from my_compat import MultipartEncoder这样导入使用

但MultipartEncoder也存在无法转化中文名的问题,所以我在代码里取了巧,先把文件名转化成可解析的字符,然后用to_string方法解析,最后把解析后的字符串转化回去

from requests_toolbelt.multipart.encoder import MultipartEncoder

from my_compat import MultipartEncoder

import urllib

import requests

import json

encoded_name = urllib.quote(file_name.encode(‘utf-8‘))//取巧做法,先转化字符

with open(res_path, ‘rb‘) as f_:

m = MultipartEncoder(

fields={‘file‘: (encoded_name, f_,

‘application/octet-stream‘)}

)

decoded_m = m.to_string()//解析时不支持中文

decoded_m = decoded_m.replace(encoded_name, file_name)//替代转化

response = requests.post(url,

data=decoded_m,

headers={‘Content-Type‘: m.content_type,

‘charset‘: ‘UTF-8‘},

verify=False)

try:

content = json.loads(response.content)

except ValueError:

content = response.content

return content, response.status_code

后来发现这样做其实很不方便,所以我就阅读MultipartEncoder的源码,发现content_type其实就是一个很简单的随机字符串的构造,而数据的字符流只要符合一定规范就可以构造,再结合requests包,写出了如下的代码,

#coding=utf8

import requests

from uuid import uuid4

import os

file_name=‘test‘

url=

boundary=uuid4().hex

header={‘Content-Type‘: ‘multipart/form-data; boundary={0}‘.format(boundary),‘charset‘: ‘UTF-8‘}

with open(r‘C:\test‘.decode(‘utf8‘), ‘r‘) as f:

content=f.readlines()

print content

content=‘‘.join(content)

datas = ‘--{0}{1}Content-Disposition: form-data; name="file"; filename="{2}"{1}Content-Type: application/octet-stream{1}{1}{3}{1}--{0}--{1}‘. format(boundary,os.linesep, file_name, content,boundary)

print repr(datas)

print header

response = requests.post(url,

data=datas,

headers=header,

verify=False)

print response.status_code,response.text

在windows上调试可以,但在linux上调试一直报错,后来把os.linesep换成指定的‘\r\n‘分隔符就可以成功了,不知道是我们公司服务器设置问题还是这个库的解析问题。

#coding=utf8

import requests

from uuid import uuid4

import os

file_name=‘test‘

url=

boundary=uuid4().hex

header={‘Content-Type‘: ‘multipart/form-data; boundary={0}‘.format(boundary),‘charset‘: ‘UTF-8‘}

with open(r‘C:\test‘.decode(‘utf8‘), ‘r‘) as f:

content=f.readlines()

print content

content=‘‘.join(content)

datas = ‘--{0}{1}Content-Disposition: form-data; name="file"; filename="{2}"{1}Content-Type: application/octet-stream{1}{1}{3}{1}--{0}--{1}‘. format(boundary,‘\r\n‘, file_name, content,boundary)

print repr(datas)

print header

response = requests.post(url,

data=datas,

headers=header,

verify=False)

print response.status_code,response.text

结合saltstack,在proxy上执行的 "salt ‘{}‘ cp.push {}".format(path, agent_id, file_path)命令,效果更佳

原文:https://www.cnblogs.com/slqt/p/10238019.html