当python请求发布数据是字符串类型时,什么是默认编码?

问题描述 投票:3回答:3

使用以下代码

payload = '''
 工作报告 
 总体情况:良好 
'''
r = requests.post("http://httpbin.org/post", data=payload)

请求发布数据是字符串类型时的默认编码是什么? UTF8还是unicode-escape?

如果我想指定一种编码类型,我是否必须自己编码并将一个bytes对象传递给参数'data'?

python python-requests
3个回答
1
投票

如果你真的尝试你的例子,你会发现:

$ python
Python 3.7.2 (default, Jan 29 2019, 13:41:02) 
[Clang 10.0.0 (clang-1000.10.44.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> payload = '''
...  工作报告 
...  总体情况:良好 
... '''
>>> r = requests.post("http://127.0.0.1:8888/post", data=payload)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/venv/lib/python3.7/site-packages/requests/api.py", line 116, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/tmp/venv/lib/python3.7/site-packages/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "/tmp/venv/lib/python3.7/site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/tmp/venv/lib/python3.7/site-packages/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "/tmp/venv/lib/python3.7/site-packages/requests/adapters.py", line 449, in send
    timeout=timeout
  File "/tmp/venv/lib/python3.7/site-packages/urllib3/connectionpool.py", line 600, in urlopen
    chunked=chunked)
  File "/tmp/venv/lib/python3.7/site-packages/urllib3/connectionpool.py", line 354, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/tmp/venv/lib/python3.7/http/client.py", line 1229, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/tmp/venv/lib/python3.7/http/client.py", line 1274, in _send_request
    body = _encode(body, 'body')
  File "/tmp/venv/lib/python3.7/http/client.py", line 160, in _encode
    (name.title(), data[err.start:err.end], name)) from None
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 2-5: Body ('工作报告') is not valid Latin-1. Use body.encode('utf-8') if you want to send it encoded in UTF-8.

Detecting the character encoding of an HTTP POST request中所述,HTTP POST的默认编码是ISO-8859-1 aka Latin-1。并且正如回溯结尾处的错误消息告诉您的那样,您可以通过编码为UTF-8 bytes字符串来强制它;但当然你的服务器也需要期待UTF-8;或者你只是发送无用的Latin-1 mojibake。

POST界面本身无法强制执行此操作,但您的服务器实际上可能要求客户端使用charset参数显式指定其内容编码;如果缺少明确的错误消息,可能会返回特定的5xx错误代码。

不那么自律,您可以让服务器尝试将传入的POST请求解码为UTF-8,如果失败则拒绝POST。


0
投票

请求uses *标准库的http.client.HTTPConnection.request发送请求。此方法将str数据编码为latin-1,但不会编码bytes

如果您提供编码输入,则应添加指定所用编码的内容类型标头;相反,如果您提供内容类型标头,则应确保正文的编码与指定的编码匹配。

来自文档:

如果指定了body,则在标题完成后发送指定的数据。它可以是str,类字节对象,打开文件对象或可迭代字节。如果body是字符串,则编码为ISO-8859-1,HTTP的默认值。如果它是类似字节的对象,则按原样发送字节。如果是文件对象,则发送文件内容;此文件对象应至少支持read()方法。如果文件对象是io.TextIOBase的实例,则read()方法返回的数据将被编码为ISO-8859-1,否则read()返回的数据将按原样发送。如果body是可迭代的,则iterable的元素将按原样发送,直到iterable耗尽为止。

* httplib在Python3中重命名为http.client


0
投票

您必须将有效负载编码为UTF-8。这是快速解决方案:

r = requests.post("http://httpbin.org/post", data=payload.encode('utf-8'))

请求使用Httplib,默认情况下将字符串编码为latin-1。字节数组不会自动编码,因此使用它们总是更好。

我还建议您在内容标题中设置charset,方式如下:

r = requests.post("http://httpbin.org/post", data=payload.encode('utf-8'),
                  headers={'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'})
© www.soinside.com 2019 - 2024. All rights reserved.