خطأ 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…

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.

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.

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:

[quote=“marcozambi, post:7, topic:98186, full:false”][/quote]
نواجه مشكلة مماثلة عند إنشاء منشور باستخدام طريقة POST.
وعندما يكون المنشور طويلًا، يظهر خطأ 414.

نستخدم واجهة برمجة تطبيقات Discourse بلغة Python لتوليد بعض المنشورات عبر واجهة برمجة تطبيقات Discourse.

يبدو أن دالة create_topic تستخدم طلب POST باستخدام المعاملات (params) بدلاً من البيانات (data).
هذا هو تعريف دالة create_topic من واجهة برمجة تطبيقات Discourse:

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 بدلاً من أن يكون جزءًا من حمولة داخلية.

هل هذا خطأ برمجي؟
كيف يمكننا إنشاء منشور طويل باستخدام حمولة بيانات بدلاً من معاملات عنوان 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

أيضًا، كما شرحتُ هنا، فإن تمرير الـ payload عبر معامل params كان خطأً من جهتي ولا ينبغي فعل ذلك.
آمل أن يكون هذا مفيدًا.

شكرًا جزيلاً على ردك السريع.

نحن نستخدم غلافًا بلغة بايثون لواجهة برمجة التطبيقات الرسمية بلغة جافاسكريبت الخاصة بمنصة ديسكورد:

يبدو أنه غلاف لواجهة ديسكورد الرسمية.

المشكلة هي أن التعريفات تستخدم params= (كما هو موضح في تعريف الدالة المستخرج من ملف clients.py).
يتم تمرير العنوان والبيانات الخام عبر params.

لقد قمنا بتغيير تعريف دالة create_post لتستخدم data=
ولكنها لا تعمل بعد ذلك.

أرى. حسنًا، يبدو أن المشكلة تكمن في تنفيذ الـ wrapper. في رأيي، لا تحتاج إلى أي wrapper. باستثناء وحدات requests و json، فإن الكود الذي نشرته هو ببساطة Python3 عادي. جرّب اتباع ذلك، ربما بتعريف دوال wrapper خاصة بك.

أرى، أنت محق.

المشكلة هي أننا لسنا ماهرين جدًا في بايثون.

لكن يبدو أن تنفيذ الغلاف غير جيد.

ولكن حتى لو قمنا بتغيير المعاملات إلى البيانات في تعريف الدالة، فإنها لا تعمل.

سنبذل جهدنا لاستخدام هذا الرمز البرمجي لإنشاء المنشور بدلاً من رمز الغلاف.

أنا لست الشخص المسؤول عن البرمجة؛ فإني أبرمج بلغة JavaScript ولغات أخرى، لكنني لا أستخدم Python.

سأحاول شرح الأمر للمبرمج (إنه مرتبك بعض الشيء؛ كان يستخدم الغلاف معتقداً أنه التطبيق الرسمي لـ Discourse API، بينما يستخدم الغلاف كلمة “post” كاسم للطريقة لإنشاء المنشور، في حين أن مكتبة Python الأساسية تستخدم كلمة “post” كاسم للطريقة لإرسال رسالة POST. أعتقد أن هذا هو ما لا يفهمه جيداً).

لقد جربنا الكود الخاص بك، لكننا نتلقى استجابة بخطأ 403.

يبدو أن هناك مشكلة في المصادقة من نوع ما.
لكننا نستخدم نفس مفتاح الـ API والمستخدم اللذين استخدمناهما سابقًا (مع غلاف الـ API) وكان ذلك يعمل…
هل لديك أي فكرة؟

سأخبر المبرمج بالتدقيق في الأمر وشرحه بشكل أفضل.

إنهم يحاولون استخدام بايثون، وليس كيرل.

النموذج الذي ذكروه أعلاه يحتوي على الترويسات الصحيحة.

مرحبًا ماركو،

أنا زميل فيرناندو. لقد طبّقت كودك ويعمل بشكل ممتاز، وقد تم حل المشكلة.

شكرًا جزيلاً!
ألبيرت.

شكرًا لكم جميعًا، وخاصةً ماركو الذي قدم كود بايثون.

الآن يعمل الأمر.
لقد ارتكبنا خطأً واستخدمنا api-key بدلاً من Api-key.

قمنا بتغيير ذلك، والآن يعمل الكود.

لا أعرف ما الخطأ في الغلاف (wrapper) الذي كنا نستخدمه (بخلاف استخدام params= بدلاً من url).

قمنا بتغيير params إلى data، لكنه لم يعمل، مع أن الكود يبدو أنه يفعل بالضبط ما قاله ماركو (ولكن باستخدام params، وهو ليس الطريقة الصحيحة).

شكرًا مرة أخرى.

ليس الأمر حساسًا لحالة الأحرف من جانبنا، أليس كذلك @blake؟

أنا لست المبرمج، ولا أعرف بايثون، بل ساعدته فقط في إصلاح الخطأ.

ربما تكون بايثون حساسة لحالة الأحرف، أو هل هناك خيار لتفعيل ذلك؟

عمل البرنامج بمجرد تغيير ذلك.

لا. يقوم Rails/Rack بتحويل جميع الرؤوس إلى أحرف كبيرة تلقائيًا. لا يوجد أي شيء في كودنا يتحقق من حساسية الأحرف.

يقوم Rails الآن بإضافة بادئة HTTP_ إلى الرأس بالإضافة إلى تحويله إلى أحرف كبيرة، لذا سيصبح الآن: request.headers[“HTTP_CONTENT_TYPE”]