web-dev-qa-db-fra.com

HTTP 400 (mauvaise demande) pour erreur logique, syntaxe non malformée

La spécification HTTP/1.1 (RFC 2616) se lit comme suit sur la signification de code d’état 400, Demande incorrecte (§10.4.1) :

La demande n'a pas pu être comprise par le serveur en raison d'une syntaxe mal formée . Le client NE DEVRAIT PAS répéter le demande sans modifications.

Il semble que de nos jours, quelques API basées sur HTTP semblent avoir l'habitude d'utiliser 400 pour signifier une erreur logical plutôt qu'une erreur syntax avec une requête. Je suppose que les API le font pour distinguer entre 400 (induit par le client) et 500 (induit par le serveur). Est-il acceptable ou incorrect d’utiliser 400 pour indiquer des erreurs non syntaxiques? Si cela est acceptable, y a-t-il une référence annotée sur la RFC 2616 qui donne plus d'informations sur l'utilisation prévue de 400?

Exemples:

60
Atif Aziz

À ce jour, le dernier projet de la spécification HTTPbis , destiné à remplacer la RFC 2616 et à la rendre obsolète, indique :

Le code d'état 400 (Bad Request) indique que le serveur ne peut pas ou ne traitera pas la demande car la syntaxe reçue est invalide, absurde, ou dépasse certaines limites sur ce que le serveur veut procéder.

Cette définition, bien que toujours sujette à modification, entérine la pratique largement utilisée consistant à réagir aux erreurs logiques avec un 400.

14
Jon

Statut 422 ( RFC 4918, Section 11.2 ) me vient à l'esprit:

Le code d’état 422 (entité non traitable) signifie que le serveur comprend le type de contenu de l’entité de demande (un code d’état 415 (type de support non supporté) est donc inapproprié) et la syntaxe de l’entité de demande est correcte ) le code d’état est inapproprié) mais n’a pas pu traiter les instructions contenues. Par exemple, cette condition d'erreur peut se produire si un corps de requête XML contient des instructions XML bien formées (c'est-à-dire syntaxiquement correctes), mais sémantiquement erronées.

60
Julian Reschke

HTTPbis traitera le libellé de 400 demandes incorrectes afin qu'il couvre également les erreurs logiques. Donc 400 incorporera 422.

De https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-18#section-7.4.1
"Le serveur ne peut ou ne traitera pas la demande en raison d'une erreur du client (syntaxe mal formée, par exemple)"

6
Andrei Neculau

Bien que j'utilise 400 pour représenter également des erreurs logiques, je dois dire que renvoyer 400 est erroné dans ce cas en raison de la façon dont la spécification est lue. Voici pourquoi, selon moi, l’erreur logique pourrait être qu’une relation avec une autre entité échouait ou n’était pas satisfaite et que des modifications apportées à l’autre entité pouvaient faire en sorte que la même chose soit transmise plus tard. C'est comme essayer (complètement hypothétique) d'ajouter un employé en tant que membre d'un service alors que cet employé n'existe pas (erreur logique). L'ajout d'employé en tant que demande de membre peut échouer car cet employé n'existe pas. Mais la même demande exacte pourrait être transmise une fois l’employé ajouté au système.

Juste mes 2 cents ... Nous avons besoin d'avocats et de juges pour interpréter le langage dans le RFC ces jours-ci :)

Merci, Vish

2
Vish

On pourrait faire valoir que le fait d'avoir des données incorrectes dans votre demande est une erreur de syntaxe, même si votre demande réelle au niveau HTTP (ligne de demande, en-têtes, etc.) est syntaxiquement valide.

Par exemple, si un service Web Restful est documenté comme acceptant les POST avec un type de contenu XML personnalisé de application/vnd.example.com.widget+xml, et que vous envoyez plutôt du texte brut de charabia ou un fichier binaire, il semble correct de traiter cela comme une erreur de syntaxe - le corps de votre demande est pas sous la forme attendue.

Je ne connais pas de références officielles à l'appui de cela, comme d'habitude, cela semble être dû à l'interprétation de la RFC 2616.

Mise à jour: Notez la formulation révisée dans RFC 7231 §6.5.1 :

Le code d’état 400 (demande incorrecte) indique que le serveur ne peut pas ou ne traitera pas la demande en raison d’une erreur perçue par le client (syntaxe de demande malformée, cadrage incorrect du message de demande ou acheminement trompeur de demande).

semble soutenir cet argument plus que le désormais obsolète RFC 2616 §10.4.1 qui disait simplement:

La requête n'a pas pu être comprise par le serveur en raison d'une syntaxe mal formée. Le client NE DEVRAIT PAS répéter la demande sans modifications.

2
Day

Sur les serveurs Java EE, un 400 est renvoyé si votre URL fait référence à une "application Web" non existante. Est-ce une "erreur de syntaxe"? Cela dépend de ce que vous entendez par erreur de syntaxe. Je dirais oui.

En anglais, les règles de syntaxe prescrivent certaines relations entre les parties du discours. Par exemple, "Bob épouse Mary" est syntaxiquement correct, car il suit le modèle {Noun + Verbe + Noun}. Alors que "Bob marriage Mary" serait syntaxiquement incorrect, {Noun + Noun + Noun}.

La syntaxe d'une URL simple est {protocole +: + // + serveur +: + port}. Selon cela, " http://www.google.com:80 " est syntaxiquement correct. 

Mais qu'en est-il de "abc: //www.google.com: 80"? Il semble suivre exactement le même schéma. Mais vraimentit est une erreur de syntaxe. Pourquoi? Parce que 'abc' n'est pas un protocole DEFINED.

Le fait est que déterminer si nous avons ou non une situation 400 nécessite plus que l’analyse des caractères, des espaces et des délimiteurs. Il doit également reconnaître quelles sont les "parties du discours" valables.

1
Panu Logic

C'est difficile.

Je pense que nous devrions;

  1. Renvoyez les erreurs 4xx uniquement lorsque le client a le pouvoir de modifier la demande, les en-têtes ou le corps, afin que la demande aboutisse dans la même intention.

  2. Renvoie les codes de plage d'erreur lorsque la mutation attendue n'a pas eu lieu, c'est-à-dire qu'un DELETE n'a pas eu lieu ou qu'un PUT n'a rien changé. Cependant, un POST est plus intéressant car la spécification indique qu'elle doit être utilisée pour créer des ressources à un nouvel emplacement ou simplement pour traiter une charge utile.

En utilisant l'exemple de la réponse de Vish, si la demande a pour but d'ajouter l'employé Priya à un service Marketing mais que Priya n'a pas été trouvée ou que son compte est archivé, il s'agit d'une erreur d'application.

La demande a bien fonctionné, les règles de votre application ont été respectées, le client a tout fait correctement, les balises ETags appariées, etc.

Comme nous utilisons HTTP, nous devons répondre en fonction de l’effet de la demande sur l’état de la ressource. Et cela dépend de la conception de votre API.

Peut-être que vous avez conçu cela.

PUT { updated members list } /marketing/members

Le renvoi d'un code de réussite indiquerait que le "remplacement" de la ressource a fonctionné; un GET sur la ressource refléterait vos changements, mais ce ne serait pas le cas.

Alors maintenant, vous devez choisir un code HTTP négatif approprié, et c'est la partie la plus délicate, car les codes sont fortement destinés au protocole HTTP, pas à votre application.

Quand je lis les codes HTTP officiels, ces deux-là me semblent appropriés.

Le code d'état 409 (conflit) indique que la demande n'a pas pu être complétée en raison d'un conflit avec l'état actuel de la ressource cible. Ce code est utilisé dans des situations où l'utilisateur peut éventuellement résoudre le conflit et soumettre à nouveau la demande. Le serveur DEVRAIT générer une charge utile comprenant suffisamment d'informations pour qu'un utilisateur puisse reconnaître la source du conflit.

Et

Le code d'état 500 (Erreur interne du serveur) indique que le serveur a rencontré une condition inattendue qui l'a empêché de répondre à la demande.

Bien que nous ayons toujours considéré le 500 comme une exception non gérée: - /

Je ne pense pas qu'il soit déraisonnable d'inventer votre propre code de statut tant qu'il est appliqué et conçu de manière cohérente.

Cette conception est plus facile à traiter.

PUT { membership add command } /accounts/groups/memberships/instructions/1739119

Vous pouvez ensuite concevoir votre API pour qu'elle réussisse toujours à créer l'instruction. Elle retourne 201 Created et un en-tête Location. Tous les problèmes liés à l'instruction sont conservés dans cette nouvelle ressource.

A POST ressemble plus à ce dernier PUT à un nouvel emplacement. A POST permet tout type de traitement d'un message par le serveur, ce qui ouvre des conceptions qui disent quelque chose comme "L'action a échoué."

Vous avez probablement déjà écrit une API qui fait cela, un site Web. Vous POST le formulaire de paiement et il a été rejeté avec succès car le numéro de carte de crédit était erroné.

Avec un POST, que vous renvoyiez 200 ou 201 en même temps que votre message de rejet dépend de la création ou non d'une nouvelle ressource et si GET est disponible à un autre endroit.

Cela dit, je serais enclin à concevoir des API qui nécessitent moins de PUT, peut-être simplement mettre à jour des champs de données, et des actions et des éléments qui invoquent des règles et des traitements ou qui ont simplement une plus grande probabilité d'échecs attendus peuvent être conçus pour POST un formulaire d’instruction.

1
Luke Puplett