我写一些代码,使管理平台的接口,我需要一些文件上传的过程的一部分,但我不知道该怎么办,从蟒蛇包含二进制文件POST请求。
我试图模仿的命令在这里 :
curl --data-binary "@image.png" -H "Content-Type: application/octet-stream" -X POST -u login:password http://redmine/uploads.xml
在蟒蛇(下同),但它似乎并没有工作。 我不知道,如果问题是主题相关的编码文件,或如果事情是错的头。
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)
基本上,你做的是正确的。 望着您链接到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
data = open('./x.png', 'rb').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
UPDATE
要找出为什么这个工程有请求,但不与urllib2的,我们必须审视东西被发送到什么区别。 看到这,我将流量发送到端口8888上运行HTTP代理(小提琴手):
使用要求
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的发送,看看当它停止工作。
这有什么好做的一个畸形上传。 HTTP错误明确规定擅自401,并告诉你CSRF令牌无效。 尝试发送一个有效的CSRF令牌上传。
更多关于CSRF令牌在这里:
什么是CSRF令牌? 什么是它的重要性,它是如何工作的?
您需要添加内容处置头,水木清华这样的(虽然我这里使用MOD-Python,但原则应该是相同的):
request.headers_out['Content-Disposition'] = 'attachment; filename=%s' % myfname
您可以使用unirest ,它提供了简单的方法来POST请求。 `
import unirest
def callback(response):
print "code:"+ str(response.code)
print "******************"
print "headers:"+ str(response.headers)
print "******************"
print "body:"+ str(response.body)
print "******************"
print "raw_body:"+ str(response.raw_body)
# consume async post request
def consumePOSTRequestASync():
params = {'test1':'param1','test2':'param2'}
# we need to pass a dummy variable which is open method
# actually unirest does not provide variable to shift between
# application-x-www-form-urlencoded and
# multipart/form-data
params['dummy'] = open('dummy.txt', 'r')
url = 'http://httpbin.org/post'
headers = {"Accept": "application/json"}
# call get service with headers and params
unirest.post(url, headers = headers,params = params, callback = callback)
# post async request multipart/form-data
consumePOSTRequestASync()
`
您可以查看完整的例子http://stackandqueue.com/?p=57