python: HTTP PUT с незакодированными двоичными данными - PullRequest
10 голосов
/ 03 января 2012

Не могу понять, как выполнить HTTP-запрос PUT со стенографическими двоичными данными в Python 2.7 со стандартными библиотеками Python.

Я думал, что смогу сделать это с помощью urllib2, но не удается , поскольку urllib2.Request ожидает данные в формате application/x-www-form-urlencoded. Я не хочу кодировать двоичные данные, я просто хочу передать их дословно, после заголовков, которые включают

Content-Type: application/octet-stream
Content-Length: (whatever my binary data length is)

Это кажется таким простым, но я продолжаю ходить кругами и не могу понять, как.

Как я могу это сделать? (кроме открытия необработанного двоичного сокета и записи в него)

Ответы [ 4 ]

12 голосов
/ 03 января 2012

Я выяснил свою проблему. Кажется, в urllib2.Request / urllib2.urlopen() (по крайней мере, в Python 2.7)

есть неясное поведение

Конструктор urllib2.Request(url, data, headers), похоже, ожидает того же типа строки в своих URL-адресах и параметрах данных.

Я давал параметру данных необработанные данные из файла read() вызова (который в Python 2.7 возвращает его в виде «простой» строки), но мой URL был случайно Unicode, потому что я конкатенировал часть URL из результата другой функции, которая возвратила строки Unicode.

Вместо того, чтобы пытаться «вывести» url из Unicode -> простых строк, он попытался «выкинуть» параметр data в Unicode, и это дало мне ошибку кодека. (как ни странно, это происходит при вызове функции urllib2.urlopen(), а не в конструкторе urllib2.Request)

Когда я изменил свой вызов функции на

# headers contains `{'Content-Type': 'application/octet-stream'}`
r = urllib2.Request(url.encode('utf-8'), data, headers)

все работало нормально.

9 голосов
/ 03 января 2012

Вы неправильно читаете документацию: urllib2.Request ожидает, что данные уже закодированы , а для POST это обычно означает формат application/x-www-form-urlencoded.Вы можете ассоциировать любые другие, двоичные данные, например:

import urllib2

data = b'binary-data'
r = urllib2.Request('http://example.net/put', data,
                    {'Content-Type': 'application/octet-stream'})
r.get_method = lambda: 'PUT'
urllib2.urlopen(r)

. Это приведет к получению требуемого запроса:

PUT /put HTTP/1.1
Accept-Encoding: identity
Content-Length: 11
Host: example.net
Content-Type: application/octet-stream
Connection: close
User-Agent: Python-urllib/2.7

binary-data
4 голосов
/ 03 января 2012

Рассматривали ли вы / пытались ли использовать httplib ?

HTTPConnection.request (метод, URL [, тело [, заголовки]])

Это отправит запрос на сервер, используя метод HTTP-запроса. метод и селектор URL. Если аргумент body присутствует, он должна быть строка данных для отправки после окончания заголовков. В качестве альтернативы это может быть объект открытого файла, в этом случае содержимое файла отправлено; этот файловый объект должен поддерживать fileno () и методы read (). Заголовок Content-Length автоматически устанавливается на правильное значение. Аргумент заголовков должен быть отображением дополнительных Заголовки HTTP для отправки с запросом.

1 голос
/ 11 февраля 2016

Этот отрезанный сработал для меня, чтобы положить изображение:

на сайте HTTPS. Если вам не нужен HTTPS, используйте Вместо этого httplib.HTTPConnection (URL).

import httplib
import ssl
API_URL="api-mysight.com"
TOKEN="myDummyToken"
IMAGE_FILE="myimage.jpg"
imageID="myImageID"
URL_PATH_2_USE="/My/image/" + imageID +"?objectId=AAA"
headers = {"Content-Type":"application/octet-stream", "X-Access-Token": TOKEN}
imgData = open(IMAGE_FILE, "rb")
REQUEST="PUT"
conn = httplib.HTTPSConnection(API_URL, context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))
conn.request(REQUEST, URL_PATH_2_USE, imgData, headers)
response = conn.getresponse()
result = response.read()
...