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 エラーが発生します。

Discourse API を Python で使用して、いくつかの投稿を生成しています。

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 に変更しようとしました。
POST の代わりに PUT を使用しようとしました。
しかし、うまくいきません。

問題は、完全な投稿が内部ペイロードではなく URL のパラメータとして渡されている点のようです。

これはバグでしょうか?
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 パラメータを通じてペイロードを渡すのは私の誤りであり、行うべきではありません。
これが役立つことを願っています。

「いいね!」 2

迅速なご対応、誠にありがとうございます。

Discourse の公式 JavaScript API への Python ラッパーを使用しています。

これは公式の Discourse ラッパーのようです。

問題は、定義で params= を使用している点です(clients.py ファイルから抽出した関数定義をご参照ください)。
title と raw データを params に渡しています。

create_post 関数の定義を data= に変更しましたが、動作しません。

なるほど。問題はおそらくラッパーの実装にあるようです。
私の意見では、ラッパーは不要です。私が投稿したコードは、requests モジュールと json モジュールを除けば、そのままの Python 3 です。
その方法で試してみてください。必要に応じて、独自のラッパー関数を定義すると良いでしょう。

「いいね!」 2

なるほど、おっしゃる通りですね。

問題は、私たちが Python にあまり精通していないことです。

しかし、ラッパーの実装が適切でないようです。

さらに、関数定義で params を data に変更しても、動作しません。

代わりにラッパーコードではなく、このコードを使って投稿を作成しようとします。

私自身はプログラムを担当しているわけではありません。私は JavaScript や他の言語でプログラミングしますが、Python ではありません。

プログラマーに方法を説明してみます(彼は少し混乱しています。公式の Discourse API 実装だと思ってラッパーを使っていましたが、ラッパーは投稿を作成するメソッドの名前として「post」を使用しているのに対し、その下にある Python ライブラリは POST メッセージを送信するメソッドの名前として「post」を使用しています。彼がうまく理解できていないのは、おそらくこの点だと思います)。

「いいね!」 2

コードを試してみましたが、403エラーが返ってきました。

認証に何らかの問題があるようです。
以前(APIラッパーを使用していた際)に使っていたのと同じAPIキーとユーザーを使用しているのに、以前は動作していました。
何か心当たりはありますか?

プログラマーに確認させて、より詳しく説明させます。

彼らはcurlではなく、Pythonを使おうとしています。

彼らが上記で言及している例には、正しいヘッダーが含まれています。

「いいね!」 2

こんにちは、マルコさん。

フェルナンドの同僚のアルベルトです。あなたのコードを実装しましたところ、問題なく動作し、問題は解決いたしました。

大変ありがとうございます!
アルベルト

「いいね!」 2

皆さん、特にPythonコードを提供してくれたMarcoに感謝します。

これで動作します。
私たちはエラーを起こし、api-keyの代わりにApi-keyを使用していました。

それを修正し、コードが動作するようになりました。

私たちが使用していたラッパーに何が問題だったのかはわかりません(params=の代わりにurlを使用していたこと以外)。paramsをdataに変更しましたが、動作しませんでした。しかし、コードはMarcoが言ったことと完全に同じことをしているようです(ただし、正しい方法ではないparamsを使用しています)。

改めてありがとうございます。

「いいね!」 3

当方では大文字小文字は区別されませんよね、@blake さん?

私はプログラマーではなく、Pythonのことも詳しくありません。ただ、エラーの修正を手伝っただけです。

もしかすると、Pythonは大文字小文字を区別するのか、それともそれを有効にするオプションがあるのでしょうか?

その部分を変更しただけで、プログラムは正常に動作しました。

いいえ。Rails/Rack はすべてのヘッダーを大文字に変換してくれます。私たちのコードで大文字小文字の区別をチェックしている箇所はありません。

Rails は現在、ヘッダーに HTTP_ を付加し、すべて大文字に変換するため、現在は request.headers[“HTTP_CONTENT_TYPE”] となります

「いいね!」 3