python使用requests库通过proxy代理post上传文件
python通过http post的方式上传文件到服务器有多种方式,使用urllib2库,poster库和requests库均可实现。此处由于环境的限制,使用requests库来实现。先上代码,我使用的是python2进行的编写
import requests
import json
f = open("./abc", "rb")
url = 'http://100.11.12.13:8989/upload'
files = {'file' : f }
headers = { "Host" : "100.11.12.13:8989" }
proxy = { 'http' : "192.168.1.156:8012"}
post_data = {}
post_data["name"] = "bob"
data = json.dumps(post_data).encode("utf-8")
r = request.post(url,proxies=proxy,data=data,files=files,headers=headers)
print(r.text)
f.close();
此处主要涉及如下方面
- 文件上传
通过post接口files参数上传,参数为字典结构,file为key值,f打开的句柄表示要上传的文件内容,此处使用了最简洁的形式,根据博客 requests上传多个文件 ,官方 推荐如下结构
{
"field1" : ("filename1", open("filePath1", "rb")),
"field2" : ("filename2", open("filePath2", "rb"), "image/jpeg"),
"field3" : ("filename3", open("filePath3", "rb"), "image/jpeg", {"refer" : "localhost"})
}
在上面的最简模式中 filename 就是filepath中的文件名。该接口参数字典可以以这种方式,支持同时上传不同key值的多个文件。
- 代理设置
proxy = { 'http' : "192.168.1.156:8012"}
该行是设置目的代理为 192.168.1.156的8012端口上的服务,我在这个位置部署了一台windows上的nginx服务器。对上传请求做代理转发。此处的 key值指定的是协议的类型,即使是http,也不限制是80端口,实际上我上述的请求服务器目的端口就不是80端口,对应的需要通过https协议进行上传时,需将key值指定为 https ,同时可能需要设置字段,
verify=False.
- 头部信息设置
但上述的设置仍然无法完成通过proxy代理进行post文件的上传,我是在python 2.7.3 版本,会提示对应页面无法访问,通过抓包发现,虽然 url中请求的目的端口是8989端口,但是Host中的信息是只有100.11.12.13,即不含有端口的信息,而nginx在进行代理转发时,是依赖Host中的信息进行代理转发的,如下
location / {
proxy_pass http://$http_host$request_uri;
}
此处应是该版本requests库的实现缺陷,故而需要在headers中再指定,headers = { “Host” : “100.11.12.13:8989” }。才能够再nginx代理转发时完成转发。
- nginx代理配置
nginx代理除了完成上述配置外,因post上传内容可能较大,可能返回nginx 413错误,即Request Entity Too large,仍然需要在http模块中增加 client上传的body的配置信息如下:
http {
...
client_max_body_size 100M;
...
}
client_max_body_size该值默认为1MB,为请求正文的允许大小,判断的是Content-Length字段的值。
参考
http://cn.python-requests.org/zh_CN/latest/user/quickstart.html