2012-01-02 31 views
10

Tôi không thể cho tôi biết cách thực hiện yêu cầu HTTP PUT với dữ liệu nhị phân đúng nguyên văn trong Python 2.7 bằng thư viện Python chuẩn.python: HTTP PUT với dữ liệu nhị phân chưa mã hóa

Tôi nghĩ tôi có thể làm điều đó với urllib2, nhưng that failsurllib2.Request hy vọng dữ liệu của nó ở định dạng application/x-www-form-urlencoded. Tôi không muốn để mã hóa dữ liệu nhị phân, tôi chỉ muốn truyền tải nó đúng nguyên văn, sau khi các tiêu đề đó bao gồm

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

Điều này có vẻ đơn giản như vậy, nhưng tôi tiếp tục đi vòng vòng và dường như không thể tìm ra làm sao.

Tôi làm cách nào để thực hiện việc này? (ngoài việc mở một ổ cắm nhị phân thô và ghi vào nó)

Trả lời

12

tôi phát hiện ra vấn đề của tôi. Dường như có một số hành vi tối nghĩa trong urllib2.Request/urllib2.urlopen() (ít nhất là bằng Python 2.7)

Hàm tạo urllib2.Request(url, data, headers) có vẻ như mong đợi cùng một loại chuỗi trong url và thông số dữ liệu của nó.

Tôi đã cung cấp dữ liệu thô tham số dữ liệu từ một cuộc gọi read() (trong Python 2.7 trả về dưới dạng chuỗi 'thuần'), nhưng url của tôi vô tình Unicode vì tôi đã ghép một phần URL kết quả của một hàm khác trả về chuỗi Unicode.

Thay vì cố gắng "downcast" url từ Unicode -> chuỗi đơn giản, nó đã cố gắng "upcast" tham số data thành Unicode và nó đã cho tôi lỗi codec. (Kỳ quặc đủ, điều này xảy ra trên cuộc gọi urllib2.urlopen() chức năng, không phải là nhà xây dựng urllib2.Request)

Khi tôi thay đổi cuộc gọi chức năng của tôi để

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

nó làm việc tốt.

+0

Tôi gặp phải [thư viện yêu cầu] (https://github.com/kennethreitz/requests) ngay hôm nay. Trong tương lai, bạn có thể muốn sử dụng nó. –

+2

Tôi đã có vấn đề chính xác, tuyệt vời, cổ vũ người đàn ông! –

4

Bạn đã xem xét/thử sử dụng httplib?

HTTPConnection.request (phương pháp, url [, cơ thể [, tiêu đề]])

This will send a request to the server using the HTTP request method method and the selector url. If the body argument is present, it should be a string of data to send after the headers are finished. Alternatively, it may be an open file object, in which case the contents of the file is sent; this file object should support fileno() and read() methods. The header Content-Length is automatically set to the correct value. The headers argument should be a mapping of extra HTTP headers to send with the request.

+0

"Bạn đã xem xét/thử dùng httplib chưa?" -- Vâng. Sẽ không làm việc, nó pukes trên dữ liệu không ascii. –

+1

Hmmm ...mở đối tượng tập tin, cũng có thể được giúp đỡ. –

+0

@ JasonS Ok, chỉ cần checkin –

9

Bạn đang hiểu sai tài liệu: urllib2.Request hy vọng các dữ liệu đã được mã hóa , và cho POST thường có nghĩa là định dạng application/x-www-form-urlencoded. Bạn có thể tự do liên kết bất kỳ khác, nhị phân dữ liệu, như thế này:

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) 

này sẽ sản xuất theo yêu cầu bạn muốn:

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 
+1

Nhưng những gì tôi nhận được là 'UnicodeDecodeError:' ascii 'codec không thể giải mã byte 0xc2 ở vị trí 0: thứ tự không nằm trong phạm vi (128) ' –

+0

btw, làm thế nào bạn nhận được yêu cầu thô được gửi từ urllib2? –

+0

@JasonS Đó là vì dữ liệu của bạn là một chuỗi * * (đối tượng 'unicode'), không phải là đối tượng' byte'. Mã hóa mã hóa chính xác bằng ['encode'] (http://docs.python.org/library/stdtypes.html#str.encode). Nó có thể hữu ích để viết chương trình trong Python 3 và sau đó backport nó vào 2.x. – phihag

1

Điều này được làm việc để tôi có thể PUT hình ảnh:

trên trang web HTTPS. Nếu bạn không cần HTTPS, thay vào đó hãy sử dụng httplib.HTTPCKết nối (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() 
Các vấn đề liên quan