use*_*641 1 python python-requests
我有一些PHP代码,它将二进制文件上传到我没有shell访问权限的远程服务器.PHP代码是:
function upload($uri, $filename) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '@' . $filename));
curl_exec($ch);
curl_close($ch);
}
Run Code Online (Sandbox Code Playgroud)
这导致标题如下:
HTTP/1.1
Host: XXXXXXXXX
Accept: */*
Content-Length: 208045596
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------360aaccde050
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用请求将此端口移植到python,我无法让服务器接受我的POST.我已尝试过使用requests.post的每种方式,但标题不会模仿上述内容.
这将成功地将二进制文件传输到服务器(可以通过观看wireshark来判断),但因为标头不是服务器所期望的,它会被拒绝.response_code虽然是200.
files = {'bulk_test2.mov': ('bulk_test2.mov', open('bulk_test2.mov', 'rb'))}
response = requests.post(url, files=files)
Run Code Online (Sandbox Code Playgroud)
请求代码产生一个标题:
HTTP/1.1
Host: XXXX
Content-Length: 160
Content-Type: multipart/form-data; boundary=250852d250b24399977f365f35c4e060
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/2.2.1 CPython/2.7.5 Darwin/13.1.0
--250852d250b24399977f365f35c4e060
Content-Disposition: form-data; name="bulk_test2.mov"; filename="bulk_test2.mov"
--250852d250b24399977f365f35c4e060--
Run Code Online (Sandbox Code Playgroud)
有关如何发出请求的任何想法都与PHP代码生成的标头匹配?
有两个很大的差异:
PHP代码发布了一个名为的字段file,您的Python代码会发布一个名为的字段bulk_test2.mov.
您的Python代码发布一个空文件.Content-Length标头是160字节,恰好是多部分边界和Content-Disposition部分标题占用的空间量.无论是bulk_test2.mov文件确实是空的,或试图将文件多次张贴无需倒带或重新打开文件对象.
要解决第一个问题,请使用字典中'file'的键files:
files = {'file': open('bulk_test2.mov', 'rb')}
response = requests.post(url, files=files)
Run Code Online (Sandbox Code Playgroud)
我只使用打开的文件对象作为值; requests在这种情况下,将直接从文件对象获取文件名.
第二个问题是你能解决的问题.确保在重复发布时不要重复使用 files.重新打开,或用于files['file'].seek(0)将读取位置倒回到开头.
该Expect: 100-continue头是一个可选的客户端功能,要求服务器确认身体上载可以继续 ; 它不是必需的标题,任何发布文件对象的失败都不会是由于requests使用此功能.如果您不使用此功能时HTTP服务器出现异常,则会违反HTTP RFC,并且您手上会遇到更大的问题.它肯定不会requests为你解决问题.
如果您确实设法发布实际文件数据,那么任何小的变化Content-Length都是由于(随机)边界在Python和PHP之间的长度不同.这是正常的,而不是上载问题的原因,除非您的目标服务器非常破碎.同样,不要试图用Python修复这种破坏.
但是,我认为你忽视了一些更简单的事情.User-Agent例如,服务器可能会将某些标题列入黑名单.您可以requests使用Session对象清除一些默认标头集:
files = {'file': open('bulk_test2.mov', 'rb')}
session = requests.Session()
del session.headers['User-Agent']
del session.headers['Accept-Encoding']
response = session.post(url, files=files)
Run Code Online (Sandbox Code Playgroud)
并看看这是否有所作为.
如果服务器由于无法处理HTTP持久连接而无法处理您的请求,您可以尝试将该会话用作上下文管理器,以确保关闭所有会话连接:
files = {'file': open('bulk_test2.mov', 'rb')}
with requests.Session() as session:
response = session.post(url, files=files, stream=True)
Run Code Online (Sandbox Code Playgroud)
你可以添加:
response.raw.close()
Run Code Online (Sandbox Code Playgroud)
好的措施.