Python Requests包中的data参数和json参数之间的区别是什么?

146

Python Requests包中的data参数和json参数有什么区别?

文档中不清楚。

这段代码是这样的吗:

import requests
import json
d = {'a': 1}
response = requests.post(url, data=json.dumps(d))

(请注意,我们在这里将dict转换为JSON!)
...与以往没有任何不同。
import requests
import json
d = {'a': 1}
response = requests.post(url, json=d)

如果是这样,那么呢?
后者会自动将Content-Type HTTP头设置为application/json吗?
3个回答

126
为了回答我的问题,看起来我上面的两个例子做了同样的事情,使用 json 参数确实将头信息中的 content-type 设置为 application/json。在我上面的第一个示例中使用 data 参数时,需要手动设置头信息中的 content-type

2
这个行为就像一个API应该有的行为一样。您也可以在此处查看https://github.com/kennethreitz/requests/blob/master/requests/models.py#L422。 - wenzul
7
同意,只是没有在代码中阅读以外的地方记录下来。 - user1507844
31
这确实是个明智的行为,但适当记录它将会很有帮助。使用字典数据时将 json=data 转换成 JSON 格式可能不太明显。我的第一反应是使用 json=json.dumps(data),因为这样更准确。然后我在远程 API 的端点上得到了不相关的错误,因为它接收到的是一个进一步编码为 JSON 的 JSON 字符串的结果(即双重转储)。由于这是一个简单的字符串,难以检测,因此仍然是有效的 JSON。使问题更加混乱的是,在记录接收端获得的内容时,无论以字符串形式还是字典形式呈现输出都是无法区分的。 - Michael Ekoka
将之前的请求代码链接更新为此链接 - jarmod
请求体中的数据在两种情况下被序列化为字符串的方式不同,与头部差异无关。其他答案解释了这种差异并提供了更准确的答案。 - hi2meuk

84
截至2021年12月,关于使用datajson的文档已经相当清楚了差异。
(在我们的小小贡献下 - 我的PR和你们的点赞证实了这曾经是一个问题。谢谢!)

附言

这并不回答原问题,但如果第一段代码略有不同:

import requests
import json
d = {'a': 1}
response = requests.post(url, data=d)

请注意,这里的dict d没有被转换为JSON字符串!
如果第二段代码相同(为了完整性而复制):
import requests
import json
d = {'a': 1}
response = requests.post(url, json=d)

...那么结果会有很大的不同。
第一段代码将生成一个请求,内容类型设置为`application/x-www-form-urlencoded`,数据以这种格式呈现:`"a=1"`。
第二段代码将生成一个请求,内容类型设置为`application/json`,实际上数据以这种格式呈现:`{"a": 1}` - 一个JSON字符串。

1
我在测试场景中遇到了这种情况,json参数通过了测试 - 去掉它可以确保我们测试有效载荷的方式就像传递数据参数一样。感谢您的贡献! loads(request.data.strip(b'"')) - Mike
1
补充一下Greg所说的,如果data参数提供的是字符串而不是字典,就像OP在上面的第一个代码中所做的那样(response = requests.post(url, data=json.dumps(d))),那么默认情况下内容类型标头不会设置为application/x-www-form-urlencoded,似乎也不会生成任何默认的内容类型标头,如此代码所示。 - Seth
1
截至目前,python-requests.org网站无法使用。文档也可在https://requests.readthedocs.io/en/latest/user/quickstart/#more-complicated-post-requests获取。 - Jimothy
谢谢@Jimothy,我已经在我的回答中更新了URL。 - Greg Dubicki

4

仅从我的经验来看,但请注意应优先使用字典的json字段,而不是将字典转储到data字段中。

同样地,仅从经验上讲,我没有研究代码本身,但似乎requests库执行了比单纯使用json.dumps更为聪明的json序列化。当在data字段中使用json.dumps时,我遇到了几个实例,导致(FastAPI)服务器返回“值不是有效的字典”错误响应。改用json字段解决了这些问题。

编辑:我今天查看了代码。如果您使用json参数,则requests库似乎只设置了Content-Type并将其转储:

from .compat import json as complexjson
content_type = 'application/json'
body = complexjson.dumps(json)
if not isinstance(body, bytes):
    body = body.encode('utf-8')

requests.compat中,json只是这样:

try:
    import simplejson as json
except ImportError:
    import json

所以我真的搞不清楚为什么使用data参数手动操作有时候会失败。¯\_(ツ)_/¯


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接