带有以下代码
payload = '''
工作报告
总体情况:良好
'''
r = requests.post("http://httpbin.org/post", data=payload)
当请求发布数据为字符串类型时,默认编码是什么?是UTF8还是unicode转义?
如果我想指定一种编码类型,是否需要自己编码并将字节对象传递给参数'data'?
答案 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'})