Python:使用二进制数据进行HTTP PUT

1 投票
3 回答
2760 浏览
提问于 2025-04-17 05:30

所以我按照另一个问题的回答的建议,调整了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 个回答

-1

根据 urllib2 的文档,你需要对字节字符串进行百分号编码。

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'),它是把unicode转换成utf-8格式的str。如果不这样做,默认的转换会使用ascii编码,而ascii编码无法处理非ascii字符。

简单来说就是... data=json.dumps(blabla).encode('utf-8') ...

1

这是因为

数据应该是标准的 application/x-www-form-urlencoded 格式的缓冲区。urllib.urlencode() 函数接受一个映射或者一系列的二元组,并返回一个这种格式的字符串。

来自 urllib2 文档

撰写回答