Python-POST-Binärdaten

Ich schreibe etwas Code, um mit redmine zu verbinden, und ich muss einige Dateien als Teil des Prozesses hochladen, aber ich bin nicht sicher, wie man eine POST-Anfrage von Python mit einer Binärdatei macht.

Ich versuche, die Befehle hier zu imitieren:

curl --data-binary "@image.png" -H "Content-Type: application/octet-stream" -X POST -u login:password http://redmine/uploads.xml 

In Python (unten), aber es scheint nicht zu funktionieren. Ich bin mir nicht sicher, ob das Problem irgendwie im Zusammenhang mit der Verschlüsselung der Datei steht oder wenn etwas mit den Headern nicht stimmt.

 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 

Ich habe Zugriff auf den Server und es sieht aus wie ein Codierungsfehler:

 ... 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) 

4 Solutions collect form web for “Python-POST-Binärdaten”

Im Grunde, was du tust, ist richtig. Wenn du dich mit den von dir verknüpften Reduzierungsdokumenten beschäftigst, so scheint es, dass das Suffix nach dem Punkt in der URL die Art der gebuchten Daten (.json für JSON, .xml für XML) bezeichnet, die mit der Antwort übereinstimmt, die du bekommst – Processing by AttachmentsController#upload as XML . Ich vermute, vielleicht gibt es einen Bug in docs und um Binärdaten zu veröffentlichen, die Sie mit http://redmine/uploads url anstelle von http://redmine/uploads.xml .

Btw, ich empfehle sehr gut und sehr beliebt Anfragen Bibliothek für http in Python. Es ist viel besser als das, was in der Standard-lib (urllib2) ist. Es unterstützt auch die Authentifizierung, aber ich habe es hier zur Kürze übersprungen.

 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 

AKTUALISIEREN

Um herauszufinden, warum dies mit Requests funktioniert, aber nicht mit urllib2 müssen wir den Unterschied in dem, was gesendet wird, untersuchen. Um dies zu sehen, schicke ich den Verkehr auf http Proxy (Fiddler), der auf Port 8888 läuft:

Verwenden von Anfragen

 import requests data = 'test data' res = requests.post(url='http://localhost:8888', data=data, headers={'Content-Type': 'application/octet-stream'}) 

wir sehen

 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 

Und mit 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) 

wir bekommen

 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 

Ich sehe keine Unterschiede, die ein anderes Verhalten rechtfertigen würden. Having said that ist es nicht ungewöhnlich für HTTP-Server zu überprüfen User-Agent Header und variieren Verhalten basierend auf seinem Wert. Versuchen Sie, die Header zu wechseln, die von Requests eins nach dem anderen gesendet werden, so dass sie dieselben sind wie die von urllib2 gesendeten und sehen, wann es aufhört zu arbeiten.

Das hat nichts mit einem fehlerhaften Upload zu tun. Der HTTP-Fehler gibt 401 nicht autorisiert an und sagt Ihnen, dass das CSRF-Token ungültig ist. Versuchen Sie, ein gültiges CSRF-Token mit dem Upload zu senden.

Mehr über csrf tokens hier:

Was ist ein CSRF-Token? Was ist ihre Bedeutung und wie funktioniert es?

Du musst den Content-Disposition-Header hinzufügen, so wie ich es benutzt habe (obwohl ich hier mod-python benutzt habe, aber das Prinzip sollte gleich sein):

 request.headers_out['Content-Disposition'] = 'attachment; filename=%s' % myfname 

Sie können unirest verwenden , es bietet eine einfache Methode, um Anfrage zu stellen. "

 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() 

"

Sie können das komplette Beispiel unter http://stackandqueue.com/?p=57 überprüfen

  • Python: Finde einen Satz zwischen einigen Website-Tags mit Regex
  • Python - Nach einem URL wurde ein Browser umgeleitet
  • Python, nicht immer volle Antwort
  • Abrufen wesentlicher Daten von einer Webseite mit Python
  • Python urllib2 Basic Auth Problem
  • HandShake Failure in Python (_ssl.c: 590)
  • Machen Sie eine http-POST-Anfrage zum Hochladen einer Datei mit python urllib / urllib2
  • Wie kann ich eine POST-Anfrage per Django senden?
  • Timeout eine Datei Download mit Python urllib?
  • Multithreading für schnelleren Download
  • Python urllib einfaches Anmeldeskript
  • Python ist die beste Programmiersprache der Welt.