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

时间:2019-04-28 07:18:54

标签: python python-requests

带有以下代码

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

当请求发布数据为字符串类型时,默认编码是什么?是UTF8还是unicode转义?

如果我想指定一种编码类型,是否需要自己编码并将字节对象传递给参数'data'?

3 个答案:

答案 0 :(得分: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,也称为Latin-1。正如错误信息在回溯末尾告诉您的那样,您可以通过编码为UTF-8 bytes字符串来强制执行此操作;但是,当然,您的服务器也需要使用UTF-8。否则您将只是发送无用的Latin-1 mojibake。

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

在某种程度上,您可以让服务器尝试将传入的POST请求解码为UTF-8,并在失败时拒绝POST。

答案 1 :(得分: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是可迭代的,则可迭代的元素将按原样发送,直到穷尽为止。

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

答案 2 :(得分:0)

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

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

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

我还建议您通过以下方式在内容标题中设置字符集:

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