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

发布于 2024-12-13 19:57:19 字数 1820 浏览 0 评论 0原文

因此,我按照另一个问题的答案的建议改编了 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)

有没有办法解决这个问题?

So I adapted urllib2 as suggested by answers to another question:

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

and it works nicely for PUT with JSON:

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

but it fails with data= binary data (partial stacktrace below):

  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)

Is there a way I can fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

苄①跕圉湢 2024-12-20 19:57:19

这是因为

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

来自 urllib2 文档

It's because

data should be a buffer in the standard application/x-www-form-urlencoded format. The urllib.urlencode() function takes a mapping or sequence of 2-tuples and returns a string in this format.

from urllib2 doc

清风疏影 2024-12-20 19:57:19

您正在尝试自动将 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 字符进行编码。

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

You are trying to automatically convert a python unicode string to a regular byte string. JSoN is always unicode, but HTTP must send bytes. If you are confident that the reciever will understand the json encoded data in a particular encoding, you can just encode it that way:

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

Note the .encode('utf-8'), which converts unicode to str in utf-8. The implicit conversion would use ascii, which cant encode non-ascii characters.

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

老子叫无熙 2024-12-20 19:57:19

根据 urllib2 文档,您需要对字节进行百分比编码-细绳。

According to the urllib2 documentation, you will need to percent-encode the byte-string.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文