如何解决Python POST二进制数据
基本上您所做的是正确的。查看链接到的redmine文档,URL中的点后的后缀似乎表示发布数据的类型(JSON为.json,XML为.xml),这与您获得的响应-
一致Processing by AttachmentsController#upload as
XML
。我猜可能是文档中存在一个错误,要发布二进制数据,您应该尝试使用http://redmine/uploads
url而不是http://redmine/uploads.xml
。
顺便说一句,我强烈建议在Python中使用非常好的和非常受欢迎的HTTP请求库。它比标准库(urllib2)中的库要好得多。它也支持身份验证,但是为了简洁起见,我跳过了它。
import requests
with open('./x.png', 'rb') as f:
data = f.read()
res = requests.post(url='http://httpbin.org/post',
data=data,
headers={'Content-Type': 'application/octet-stream'})
# let's check if what we sent is what we intended to send...
import json
import base64
assert base64.b64decode(res.json()['data'][len('data:application/octet-stream;base64,'):]) == data
更新
为了弄清楚为什么它适用于请求而不适用于urllib2,我们必须检查发送内容的差异。要查看此信息,我将流量发送到端口8888上运行的http代理(fiddler):
使用请求
import requests
data = 'test data'
res = requests.post(url='http://localhost:8888',
data=data,
headers={'Content-Type': 'application/octet-stream'})
我们看
POST http://localhost:8888/ HTTP/1.1
Host: localhost:8888
Content-Length: 9
Content-Type: application/octet-stream
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/1.0.4 cpython/2.7.3 Windows/Vista
test data
并使用urllib2
import urllib2
data = 'test data'
req = urllib2.Request('http://localhost:8888', data)
req.add_header('Content-Length', '%d' % len(data))
req.add_header('Content-Type', 'application/octet-stream')
res = urllib2.urlopen(req)
我们得到
POST http://localhost:8888/ HTTP/1.1
Accept-Encoding: identity
Content-Length: 9
Host: localhost:8888
Content-Type: application/octet-stream
Connection: close
User-Agent: Python-urllib/2.7
test data
我看不出有任何差异可以保证您观察到不同的行为。话虽如此,http服务器检查User-
Agent
标头并根据其值改变行为的情况并不少见。尝试一个接一个地更改请求发送的标头,使其与urllib2发送的标头相同,然后查看何时停止工作。
解决方法
我正在编写一些代码来与Redmine交互,并且作为过程的一部分,我需要上传一些文件,但是我不确定如何从包含二进制文件的python发出POST请求。
我正在尝试模仿这里的命令:
curl --data-binary "@image.png" -H "Content-Type: application/octet-stream" -X POST -u login:password http://redmine/uploads.xml
在python中(如下),但它似乎不起作用。我不确定问题是否与编码文件有关,或者标题是否有问题。
import urllib2,os
FilePath = "C:\somefolder\somefile.7z"
FileData = open(FilePath,"rb")
length = os.path.getsize(FilePath)
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None,'http://redmine/','admin','admin')
auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
request = urllib2.Request( r'http://redmine/uploads.xml',FileData)
request.add_header('Content-Length','%d' % length)
request.add_header('Content-Type','application/octet-stream')
try:
response = urllib2.urlopen( request)
print response.read()
except urllib2.HTTPError as e:
error_message = e.read()
print error_message
我可以访问服务器,它看起来像是编码错误:
...
invalid byte sequence in UTF-8
Line: 1
Position: 624
Last 80 unconsumed characters:
7z¼¯'ÅÐз2^Ôøë4g¸R<süðí6kĤª¶!»=}jcdjSPúá-º#»ÄAtD»H7Ê!æ½]j):
(further down)
Started POST "/uploads.xml" for 192.168.0.117 at 2013-01-16 09:57:49 -0800
Processing by AttachmentsController#upload as XML
WARNING: Can't verify CSRF token authenticity
Current user: anonymous
Filter chain halted as :authorize_global rendered or redirected
Completed 401 Unauthorized in 13ms (ActiveRecord: 3.1ms)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。