python:具有二进制数据的HTTP PUT

时间:2011-11-02 15:51:47

标签: python http binary put

所以我根据answers to another question的建议修改了urllib2:

class HttpRequest(urllib2.Request):
  def __init__(self, *args, **kwargs):
    self._method = kwargs.pop('method', 'GET')
    urllib2.Request.__init__(self, *args, **kwargs)
  def get_method(self):
    return self._method

它适用于带有JSON的PUT:

req = HttpRequest(url=url, method='PUT', 
    data=json.dumps(metadata))
response = urllib2.urlopen(req)

但它失败了data=二进制数据(下面的部分堆栈跟踪):

  File "c:\appl\python\2.7.2\lib\urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "c:\appl\python\2.7.2\lib\urllib2.py", line 394, in open
    response = self._open(req, data)
  File "c:\appl\python\2.7.2\lib\urllib2.py", line 412, in _open
    '_open', req)
  File "c:\appl\python\2.7.2\lib\urllib2.py", line 372, in _call_chain
    result = func(*args)
  File "c:\appl\python\2.7.2\lib\urllib2.py", line 1199, in http_open
    return self.do_open(httplib.HTTPConnection, req)
  File "c:\appl\python\2.7.2\lib\urllib2.py", line 1168, in do_open
    h.request(req.get_method(), req.get_selector(), req.data, headers)
  File "c:\appl\python\2.7.2\lib\httplib.py", line 955, in request
    self._send_request(method, url, body, headers)
  File "c:\appl\python\2.7.2\lib\httplib.py", line 989, in _send_request
    self.endheaders(body)
  File "c:\appl\python\2.7.2\lib\httplib.py", line 951, in endheaders
    self._send_output(message_body)
  File "c:\appl\python\2.7.2\lib\httplib.py", line 809, in _send_output
    msg += message_body
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 10: ordinal
 not in range(128)

我有办法解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

这是因为

  

数据应该是标准application / x-www-form-urlencoded格式的缓冲区。 urllib.urlencode()函数采用2元组的映射或序列,并以此格式返回一个字符串。

来自urllib2 doc

答案 1 :(得分:1)

您正在尝试自动将python unicode字符串转换为常规字节字符串。 JSoN始终是unicode,但HTTP必须发送字节。如果您确信接收方能够理解特定编码中的json编码数据,您可以按照这种方式对其进行编码:

>>> urllib2.urlopen(urllib2.Request("http://example.com", data=u'\u0ca0'))
Traceback (most recent call last):
  ...
UnicodeEncodeError: 'ascii' codec cannot encode character u'\u0ca0' in position 0: ordinal not in range(128)
>>> urllib2.urlopen(urllib2.Request("http://example.com", 
...                                 data=u'\u0ca0'.encode('utf-8')))
<addinfourl at 15700984 whose fp = <socket._fileobject object at 0xdfbe50>>
>>> 

请注意.encode('utf-8'),它会在utf-8中将unicode转换为str。隐式转换将使用ascii,它不能编码非ascii字符。

tl; dr ... data=json.dumps(blabla).encode('utf-8') ...

答案 2 :(得分:-1)

根据urllib2 documentation,您需要对字节串进行百分比编码。