为什么 HTTP POST 请求正文需要在 Python 中使用 JSON 编码?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15694120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 20:42:42  来源:igfitidea点击:

Why does HTTP POST request body need to be JSON enconded in Python?

pythonhttppython-requests

提问by acpigeon

I ran into this issue when playing around with an external API. I was sending my body data as a dictionary straight into the request and was getting 400 errors:

我在使用外部 API 时遇到了这个问题。我将我的身体数据作为字典直接发送到请求中,并收到 400 个错误:

data = {
  "someParamRange": {
    "to": 1000, 
    "from": 100
  }, 
  "anotherParamRange": {
    "to": True, 
    "from": False
  }
}

When I added a json.dumps wrap, it works:

当我添加一个 json.dumps 包装时,它可以工作:

data = json.dumps({
  "someParamRange": {
    "to": 1000, 
    "from": 100
  }, 
  "anotherParamRange": {
    "to": True, 
    "from": False
  }
})

I don't entirely understand why this is necessary, as dictionaries and JSON objects are syntactically identical. Can someone help me understand what is going on behind the scenes here?

我不完全理解为什么这是必要的,因为字典和 JSON 对象在语法上是相同的。有人可以帮助我了解这里的幕后情况吗?

For completeness, here are my headers:

为了完整起见,这是我的标题:

headers = {'API-KEY': 'blerg', 'Accept-Encoding': 'UTF-8', 'Content-Type': 'application/json', 'Accept': '*/*', 'username': 'user', 'password': 'pwd'}

EDIT:

编辑:

I didn't mention this earlier but now I feel that it may be relevant. I am using the Python Requests library, and another post seems to suggest that you should never have to encode parameters to a request object: https://stackoverflow.com/a/14804320/1012040

我之前没有提到这一点,但现在我觉得这可能是相关的。我正在使用 Python 请求库,另一篇文章似乎建议您永远不必将参数编码为请求对象:https: //stackoverflow.com/a/14804320/1012040

"Regardless of whether GET/POST you never have to encode parameters again, it simply takes a dictionary as an argument and is good to go."

“无论是否使用 GET/POST,您都不必再次对参数进行编码,它只需要一个字典作为参数,就可以了。”

Seems like serialization shouldn't be necessary?

似乎不需要序列化?

My request object:

我的请求对象:

response = requests.post(url, data=data, headers=headers)

采纳答案by Rob?

Apparently your API requires JSON-encoded and not form-encoded data. When you pass a dictin as the dataparameter, the data is form-encoded. When you pass a string (like the result of json.dumps), the data is not form-encoded.

显然,您的 API 需要 JSON 编码的数据,而不是表单编码的数据。当您传入 adict作为data参数时,数据是表单编码的。当您传递一个字符串(如 的结果json.dumps)时,数据不是表单编码的。

Consider this quote from the requests documentation:

考虑请求文档中的引用:

Typically, you want to send some form-encoded data — much like an HTML form. To do this, simply pass a dictionary to the data argument. Your dictionary of data will automatically be form-encoded when the request is made.

There are many times that you want to send data that is not form-encoded. If you pass in a string instead of a dict, that data will be posted directly.

For example, the GitHub API v3 accepts JSON-Encoded POST/PATCH data:

通常,您希望发送一些表单编码的数据 — 很像 HTML 表单。为此,只需将字典传递给 data 参数。发出请求时,您的数据字典将自动进行表单编码。

很多时候您想要发送非表单编码的数据。如果您传入一个字符串而不是一个字典,该数据将被直接发布。

例如,GitHub API v3 接受 JSON 编码的 POST/PATCH 数据:

>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}

>>> r = requests.post(url, data=json.dumps(payload))

Refs:

参考:

回答by Piotr Hajduga

Although they seem syntatically itentical there is a difference: JSON is a string representation of serialized object; in this case Python dict. In this example you need to send serialized data in a form of string and thus json.dumps is necessary to perform the serialization.

尽管它们在语法上看起来是一致的,但还是有区别的:JSON 是序列化对象的字符串表示;在这种情况下,Python 字典。在这个例子中,你需要以字符串的形式发送序列化数据,因此需要 json.dumps 来执行序列化。

edit

编辑

As suggested in comments to the question it is relative to used API, but nevertheless the serialization must be done somewhere along the way to send an object over the wire.

正如对问题的评论所建议的那样,它与使用的 API 相关,但是必须在通过网络发送对象的过程中的某个地方完成序列化。