通过 API 发布/更新时出现错误 414

Hello everybody!
When trying to post or update a message whose content exceeds a certain size (the exact size I cannot detemine yet - is there a way to check this?) NGINX refuses to accept the POST or PUT requests and returns Error 414.
Is there a way to change (permanently) the default configuration delivered with the Discourse image, so that a larger payload size (at least matching the default 32000 characters in the admin settings) is accepted via API?

Have you checked the settings for “max post size”? There is also discussion here about increasing it.

If your posts via the API are getting cut off smaller than that, I’d be surprised.

Yep, I did. It’s currently set to the default value of 32000 characters and I’m trying to push via API a payload of about 6000 characters. I think that the error comes from NGINX and not from Discourse…

1 个赞

After a bit of searching online I found that the problem might be related to the size of URL of the PUT request performed when I update a post via API.
This is actually rendering ineffective the setting “max post length” in Discourse admin, currently at the default value of 32000 characters.
Would it be possible to change the nginx template matching the web server configuration with the default Discourse configuration?


You can change nginx settings in the yml file. You can look in the discourse_docker/templates directory for some examples.

I usually edit them in the container to debug and then apply those settings to new containers in app.yml.

3 个赞

Just to document what I did for future visitors, I have manually added the options suggested in the topics linked in my previous message.

client_header_buffer_size 64k;
large_client_header_buffers 4 64k;

The values might be different for other users, but they look more than enough for my needs.

These options shall be manually added to the /etc/nginx/conf.d/discourse.conf NGINX configuration file, and after having restarted nginx service in the container, the problem will be solved.

Obviously this has to be redone manually at every container rebuild, unless this setting is added to the official web templates.

1 个赞

One last post - the error was caused by me, hence no change to the templates is needed, at all! :expressionless:

I’m placing my API requests using the requests python library, and I was submitting the payload using parameter params=payload rather than data=payload, hence my oversized payload was handled in the “wrong” way.

I changed my call from this

r = requests.put(apiWebsite + '/posts/' + str(apiPost), params=payload)

to this

r = requests.put(apiWebsite + '/posts/' + str(apiPost), data=payload)

Sorry! :blush:

8 个赞

[quote=“marcozambi, post:7, topic:98186, full:false”][/quote]
我们在使用 POST 方法创建帖子时遇到了类似的问题。
当帖子内容较长时,会出现 414 错误。

我们使用 Python 的 Discourse API 来生成一些帖子。

create_post 函数似乎是通过 params 而非 data 发送 POST 请求。
这是 Discourse API 中 create_post 的定义:

def create_topic(self, title, raw, category=None, created_at=None):
        response = self._request('POST', 'posts.json', params={
            'title': title,
            'raw': raw,
            'category': category,
            'created_at': created_at,
        })

我们尝试将函数定义中的 params 改为 data。

我们也尝试过使用 PUT 而不是 POST。
但都不起作用。

问题似乎在于完整的帖子内容被作为参数传递到了 URL 中,而不是作为内部负载(payload)发送。

这是一个 bug 吗?
我们该如何使用数据负载(data payload)而不是 URL 参数来创建长帖子?

嗯,我不太清楚你使用的是哪种模块来提交 POST 请求。我使用的是 requests 库,并按如下方式准备 POST 请求。

POST 方法用于创建新帖子;PUT 方法用于修改现有帖子。
请在此处查看 API 文档:https://docs.discourse.org/

import requests, json

headers = {
    'Content-Type': 'application/json',
    'Api-key': envDiscourseKey, # 通过此变量传递的 API 密钥
    'Api-username': envDiscourseUsername # 通过此变量传递的 API 用户名
}

tags = ['first-tag','second-tag']

payload = {
	'title': '示例标题',
	'category': 123,
	'tags': tags,
	'raw': '帖子的原始文本'
}

r = requests.post('https://www.yourwebsite.xyz/posts', headers=headers, data=json.dumps(payload))
returnedData = r.json()
status = r.status_code

另外,正如我 在此处解释的那样,通过 params 参数传递 payload 是我之前的一个错误,不应这样做。
希望这能帮到你。

2 个赞

非常感谢您的快速回复。

我们使用的是 Discourse 官方 JavaScript API 的 Python 封装:

它似乎是官方 Discourse 封装的一个变体。

问题在于,在定义中它使用了 params=(正如您在从 clients.py 文件提取的函数定义中所见)。
它将标题和原始数据作为 params 传递。

我们将 create_post 函数的定义改为 data=,但之后它无法正常工作。

明白了。看来问题出在封装器的实现上。依我看,你根本不需要任何封装器。除了 requests 和 json 模块外,我发布的代码就是纯粹的 Python 3。试着直接使用它,或许可以定义你自己的封装函数。

2 个赞

我明白了,你说得对。

问题在于我们对 Python 不够熟练。

不过,看起来这个封装器的实现确实不够好。

而且,即使我们在函数定义中将 params 改为了 data,它仍然无法正常工作。

我们将尝试使用此代码来创建帖子,而不是使用包装器代码。

我并不是负责编写该程序的人。我使用 JavaScript 和其他语言进行编程,但不使用 Python。

我会尝试向程序员解释如何实现这一点(他有些困惑,因为他一直使用包装器,误以为那是官方的 Discourse API 实现。包装器使用 post 作为创建帖子方法的名称,而底层的 Python 库 request 使用 post 作为发送 POST 请求方法的名称。我认为他不太理解的就是这一点)。

2 个赞

我们已尝试运行您的代码,但收到 403 错误响应。

看起来存在某种授权问题。
但我们使用的是之前(通过 API 包装器)成功使用过的相同 API 密钥和用户…
您有什么建议吗?

我会让程序员进一步检查并做出更详细的说明。

他们试图使用 Python,而不是 curl。

他们上面提到的示例包含了正确的请求头。

2 个赞

你好,Marco,

我是 Fernando 的同事。我已经实现了你的代码,运行正常,问题已解决。

非常感谢!
Albert。

2 个赞

感谢大家,特别感谢 Marco 提供的 Python 代码。

现在可以正常运行了。
我们犯了一个错误,使用了 api-key 而不是 Api-key。

我们修正了这一点,代码现在可以正常工作。

我不知道我们之前使用的封装器(wrapper)出了什么问题(除了使用了 params= 而不是 url)。
我们将 params 改为了 data,但依然无法工作。不过,代码似乎确实按照 Marco 所说的执行了(只是使用了 params,这并不是正确的方式)。

再次感谢。

3 个赞

在我们这边它不区分大小写,对吧 @blake

我不是程序员,不懂 Python,只是帮他修复了错误。

也许是 Python 区分大小写,或者有选项可以启用它?

程序只修改了那个地方就能运行了。

不会。Rails/Rack 会为我们将所有请求头转换为大写。我们的代码中没有任何地方在检查大小写敏感性。

[Rails 现在会在转换请求头为大写的同时附加 HTTP_ 前缀,因此现在应该是:request.headers[“HTTP_CONTENT_TYPE”]](https://stackoverflow.com/a/35326000/588458)

3 个赞