Erreur 414 lors de la publication/mise à jour via l'API

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 « J'aime »

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 « J'aime »

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 « J'aime »

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 « J'aime »

[quote=“marcozambi, post:7, topic:98186, full:false”][/quote]
Nous rencontrons un problème similaire lors de la création d’un message en utilisant la méthode POST.
Et lorsque le message est long, une erreur 414 se produit.

Nous utilisons l’API Discourse en Python pour générer certains messages via l’API Discourse.

La fonction create_topic nous semble envoyer une requête POST avec des paramètres (params) au lieu de données (data).
Voici la définition de create_topic issue de l’API 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,
        })

Nous avons essayé de remplacer params par data dans la définition de la fonction.

Nous avons également essayé d’utiliser PUT au lieu de POST.
Mais cela ne fonctionne pas.

Le problème semble être que l’intégralité du message est transmise en tant que paramètres dans l’URL plutôt que dans un corps de requête interne.

S’agit-il d’un bug ?
Comment pouvons-nous créer un message long en utilisant un corps de données (data payload) au lieu de paramètres d’URL ?

Hmm, ce n’est pas très clair pour moi quel type de module vous utilisez pour soumettre votre requête POST. J’utilise requests et je prépare une requête POST comme je le montre ci-dessous.

La méthode POST sert à créer de nouveaux sujets ; PUT sert à modifier des sujets existants.
Veuillez consulter la documentation de l’API ici : https://docs.discourse.org/

import requests, json

headers = {
    'Content-Type': 'application/json',
    'Api-key': envDiscourseKey, # Clé API passée dans cette variable
    'Api-username': envDiscourseUsername # Utilisateur API passé dans cette variable
}

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

payload = {
	'title': 'Titre exemple',
	'category': 123,
	'tags': tags,
	'raw': 'Texte brut de votre sujet'
}

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

De plus, comme je l’ai expliqué ici, transmettre le payload via le paramètre params était une erreur de ma part et ne doit pas être fait.
J’espère que cela vous aidera.

2 « J'aime »

Merci beaucoup pour votre réponse rapide.

Nous utilisons un wrapper Python pour l’API JavaScript officielle de Discourse :

Il semble s’agir d’un wrapper de l’API officielle de Discourse.

Le problème est que dans les définitions, il utilise params= (comme vous pouvez le voir dans la définition de la fonction extraite du fichier clients.py). Il passe le titre et les données brutes dans params.

Nous avons modifié la définition de la fonction create_post pour utiliser data=, mais cela ne fonctionne pas.

Je vois. Eh bien, il semble que le problème réside dans l’implémentation de l’enveloppe.
À mon avis, vous n’avez besoin d’aucune enveloppe. Mis à part les modules requests et json, le code que j’ai posté est du Python 3 tout court.
Essayez de procéder ainsi, peut-être en définissant vos propres fonctions d’enveloppe.

2 « J'aime »

Je vois, vous avez raison.

Le problème est que nous ne sommes pas très compétents en Python.

Mais il semble que l’implémentation de l’wrapper ne soit pas bonne.

Même si nous avons changé params en data dans la définition de la fonction, cela ne fonctionne pas.

Nous allons essayer d’utiliser ce code pour créer le message plutôt que le code du wrapper.

Je ne suis pas celui qui réalise le programme ; je programme en JavaScript et dans d’autres langages, mais pas en Python.

Je vais essayer d’expliquer au programmeur comment procéder (il est un peu confus : il utilisait le wrapper en pensant qu’il s’agissait de l’implémentation officielle de l’API Discourse. Le wrapper utilise ‘post’ comme nom de la méthode pour créer un message, tandis que la bibliothèque Python sous-jacente utilise ‘post’ comme nom de la méthode pour envoyer une requête POST. Je pense que c’est ce qu’il ne comprend pas bien).

2 « J'aime »

Nous avons testé votre code, mais nous recevons une erreur 403 en réponse.

Il semble qu’il y ait un problème d’autorisation.
Mais nous utilisons la même clé API et le même utilisateur que précédemment (avec le wrapper API), et cela fonctionnait…
Avez-vous une idée ?

Je dirai au programmeur de vérifier et d’expliquer cela plus clairement.

Ils essaient d’utiliser Python, pas curl.

L’exemple qu’ils mentionnent ci-dessus contient les en-têtes corrects.

2 « J'aime »

Bonjour Marco,

Je suis le collègue de Fernando. J’ai implémenté votre code et tout fonctionne parfaitement ; le problème est résolu.

Merci beaucoup !
Albert.

2 « J'aime »

Merci à tous, et tout particulièrement à Marco qui a fourni le code Python.

Maintenant, cela fonctionne.
Nous avons fait une erreur et utilisé api-key au lieu de Api-key.

Nous avons corrigé cela et le code fonctionne.

Je ne sais pas ce qui clochait dans le wrapper que nous utilisions (en dehors de l’utilisation de params= au lieu de url).
Nous avons remplacé params par data, mais cela n’a pas fonctionné. Pourtant, le code semble faire exactement ce que Marco dit (mais en utilisant params, ce qui n’est pas la bonne méthode).

Merci encore.

3 « J'aime »

Ce n’est pas sensible à la casse de notre côté, n’est-ce pas @blake ?

Je ne suis pas le programmeur, je ne connais pas Python, j’ai juste aidé à corriger l’erreur.

Peut-être que Python est sensible à la casse ou qu’il existe une option pour l’activer ?

Le programme a fonctionné simplement en modifiant cela.

Non. Rails/Rack convertit tous les en-têtes en MAJUSCULES pour nous. Rien dans notre code ne vérifie la sensibilité à la casse.

Rails attache désormais HTTP_ à l’en-tête et le convertit en majuscules, donc cela donnerait maintenant : request.headers[“HTTP_CONTENT_TYPE”]

3 « J'aime »