编辑帖子时正确的`content-type`是什么?

大家好,我可以在通过 API 更新帖子时使用 application/json 作为 Content-Type 吗?文档 说可以,但我开始觉得 我不行……

我总是收到 [\"BAD CSRF\"] 错误,完全不知道这是什么意思。


如果我需要使用 multipart/form-data,各位有什么关于如何构建 PUT 请求的提示吗?特别是 data 部分。

header = CaseInsensitiveDict()
header["Authorization"] = '{"api-key": "longapikey", "api-username": "myusername"}'
{
  "post": {
      "raw": "很棒的帖子,但这是帖子正文的更新",
      "edit_reason": "我改了它,因为我可以。"
   }
}

resp = requests.put(url, headers=headers, data=data)

谢谢!

你需要将 Api-Key 和 Api-Username 作为独立的标头发送,而不是放在 Authorization 标头中。类似下面的方式应该能更好地工作:

header = CaseInsensitiveDict()
header["Api-Key"] = 'longapikey'
header["Api-Username"] = 'myusername'

这看起来和你之前提到的主题中的问题相同:

谢谢你的回复,David。

这太奇怪了。当我按照你展示的方式格式化请求头时,我得到的是:

{"errors":["您无权查看请求的资源。API 用户名或密钥无效。"],"error_type":"invalid_access"}

但如果我加上 [\"Authorization\"],就能正常工作。

这是一个简单的 GET 请求,但我仍然无法执行 PUT 操作。

按理说,适用于某个操作的请求头也应该适用于所有操作(前提是密钥是全局的——确实如此)。所以我目前不太担心请求头的问题——还是我应该担心呢?

谢谢!

既然你在错误地使用 Authorization 头时 GET 请求都能正常工作,那么你的 PUT 请求很可能存在格式错误。GET 请求之所以能成功,是因为你根本不需要授权即可发起该请求。即使你传入了 Authorization 头,我们甚至都不会去检查它。对于公共端点的 GET 请求,即使不带任何头信息也能正常工作。

@pedroleaoc 这里有一个简单的 Python 脚本示例,演示了如何进行身份验证请求,以及如何为 PUT/POST 请求发送请求数据。

# discourse-api-demo.py
import requests
from requests.structures import CaseInsensitiveDict

# 基本的 GET 请求到公共 URL,无需头部信息。
url = "http://localhost:3000/posts/10.json"

resp = requests.get(url)

print(resp.status_code)
print(resp.content)

# 到私有端点的 GET 请求。需要身份验证头部信息。
url = "http://localhost:3000/admin/users/list/active.json"
headers = {'Api-Username': 'system', 'Api-Key': '5c1c57915e2...'}
resp = requests.get(url, headers=headers)

print(resp.status_code)
print(resp.content)

# 带有请求体的 PUT 请求
url = "http://localhost:3000/posts/10.json"
data = { 'raw': "很棒的帖子,但这里是帖子正文的更新", 'edit_reason': "我修改了它,因为我可以。" }

resp = requests.put(url, headers=headers, json=data)
print(resp.status_code)
print(resp.content)

来自 Quickstart — Requests 2.33.1 documentation

您无需自行对 dict 进行编码,也可以直接使用 json 参数(在 2.4.2 版本中添加)传递它,它将被自动编码:

url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, json=payload)

注意,如果传递了 datafilesjson 参数将被忽略。

在请求中使用 json 参数会将请求头中的 Content-Type 更改为 application/json

哎呀,当然!并非所有 GET 请求都需要 Authorization!
这个提示太棒了,我会去研究一下。谢谢!

通过逆向工程我已经知道的事情:

  • 使用 api-key 而不是 api_key
  • PUT 请求需要设置 \"content-type\": \"application/x-www-form-urlencoded\"
  • 数据不是 JSON 格式(它是经过编码的,虽然我还没找到正确的编码方式)

请参阅我在此帖正上方的 帖子。你可以在请求中使用 json=data 代替 data=data 格式,Python 的 requests 库会自动处理 content-type,并将其设置为 application/json,这正是你应该使用的格式。

太棒了,我现在可以编辑我的帖子了!感谢您的帮助!

还有一个问题:我目前使用的密钥是 global。当我尝试使用仅具有 writeread 权限的密钥时,会收到以下错误:您无权查看请求的资源。API 用户名或密钥无效。。当我通过 GUI 编辑帖子时,除了实际编辑帖子的请求(posts/post_id.json)之外,似乎还有一个指向该主题 URL 的 PUT 请求,而使用受限 API 密钥无法重现这一请求,只有使用 global 密钥才行。不过,我不明白为什么即使没有 GUI 中出现的这个额外 PUT 请求,我也无法通过 API 编辑帖子。

编辑:从技术上讲,我的 API 密钥覆盖了 /t/:slug/:topic_id,而那个 PUT 请求正是指向这里的。

您的 API 密钥是否已选择“编辑帖子”权限范围?

不!我甚至没有那个选项!我会去查一下,再次感谢你的帮助。