我正在编写一些与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)
您需要添加内容处置头,smth如下(虽然我在这里使用了mod python,但原理应该是相同的):
request.headers_out['Content-Disposition'] = 'attachment; filename=%s' % myfname
这与格式错误的上传无关。HTTP错误明确指定401未经授权,并告诉您CSRF令牌无效。请尝试随上载发送有效的CSRF令牌。
有关csrf令牌的更多信息,请参见:
什么是CSRF令牌?它的重要性是什么?它是如何工作的?
基本上你所做的是正确的。查看您链接到的redmine文档,url中点后的后缀似乎表示发布数据的类型(.json表示json,.xml表示xml),这与您得到的响应一致-由AttachmentsController处理#上传为xml
。我猜文档中可能有一个bug,要发布二进制数据,您应该尝试使用http://redmine/uploads
url而不是http://redmine/uploads.xml
。
顺便说一句,我强烈推荐非常好和非常受欢迎的Python超文本传输协议请求库。它比标准库(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服务器检查用户代理
头并根据其值改变行为并不罕见。尝试逐个更改请求发送的头,使其与urllib2发送的头相同,并查看它何时停止工作。
问题内容: 我正在使用python shell来解决print命令在python中的工作方式。 当我输入 打印01 1 打印010 8 打印0100 64 打印030 24 这里发生了什么?只是基数2?为什么第二个位置的“一个”打印为8?如果不是二进制,应该不是2吗? 问题答案: 以0开头的数字在Python 2中将其标记为八进制。这被认为是令人困惑,令人惊讶且不一致的,因为以0x开头会将其标记为
主要内容:二进制数、八进制数和十六进制数的表示,二进制数、八进制数和十六进制数的输出C语言中的整数除了可以使用十进制,还可以使用二进制、八进制和十六进制。 二进制数、八进制数和十六进制数的表示 一个数字默认就是十进制的,表示一个十进制数字不需要任何特殊的格式。但是,表示一个二进制、八进制或者十六进制数字就不一样了,为了和十进制数字区分开来,必须采用某种特殊的写法,具体来说,就是在数字前面加上特定的字符,也就是加前缀。 1) 二进制 二进制由 0 和 1 两个数字组成,使用时必须以
问题内容: 有谁知道如何在Java中添加两个以二进制形式输入的二进制数字? 例如,。 问题答案: 使用。
二进制数组(ArrayBuffer对象、TypedArray视图和DataView视图)是JavaScript操作二进制数据的一个接口。这些对象早就存在,属于独立的规格(2011年2月发布),ES6将它们纳入了ECMAScript规格,并且增加了新的方法。 这个接口的原始设计目的,与WebGL项目有关。所谓WebGL,就是指浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量的、
问题内容: 我知道用和 将小数转换为二进制(在这里我取32位结果的低16位)。 我想做的是另一种方法,并采用16位二进制补码二进制字符串并将其转换为十进制。 即 而不是 我该怎么做? 问题答案: 您需要将结果读取到中。 此打印。
问题内容: 我正在编写一些代码来与Redmine交互,并且作为过程的一部分,我需要上传一些文件,但是我不确定如何从包含二进制文件的python发出POST请求。 我正在尝试模仿这里的命令: 在python中(如下),但它似乎不起作用。我不确定问题是否与编码文件有关,或者标题是否有问题。 我可以访问服务器,它看起来像是编码错误: 问题答案: 基本上您所做的是正确的。查看链接到的redmine文档,U