
J'ai longtemps voulu écrire cet article. Je me demandais toujours de quel côté entrer plus correctement. Mais, tout à coup, récemment, un article similaire est paru sur Habré, qui a provoqué une tempête dans un verre. Ce qui m'a le plus surpris, c'est le fait que l'article a commencé à être publié avec des inconvénients, même s'il n'a même pas déclaré quelque chose, mais a plutôt soulevé la question de l'utilisation des codes de réponse du serveur Web dans REST. Le débat s'est enflammé. Et l'apothéose était que l'article était en ébauche ... des kilo-octets de commentaires, d'opinions, etc. vient de disparaître. Beaucoup sont devenus des victimes du karmo, considérez, pour rien :)
En général, c'est le sort de cet article qui m'a poussé à écrire celui-ci. Et j'espère vraiment que ce sera utile et clarifiera beaucoup.
Je vous préviens, tout ce qui est écrit ci-dessous est une véritable expérience, pas un acte d'équilibre cognitif. Et donc, ils ont conduit.
HTTP
La première chose à faire est de séparer très clairement les couches. La couche transport est http. Eh bien, en fait, REPOS. C'est une chose fondamentalement importante pour tout accepter et «vous-même». Parlons seulement de http en premier.
J'ai utilisé le terme «couche de transport». Et je n'ai pas fait de réservation. Le fait est que http lui-même implémente les fonctions de transport des requêtes vers le serveur et du contenu vers le client, indépendamment de tcp / ip. Oui, il est basé sur TCP / IP. Et il semble, il faut le considérer comme son transport. Mais non. Et voici pourquoi - les connexions de socket ne sont pas directes, c'est-à-dire ce n'est pas une connexion client-serveur. La demande http et la réponse http peuvent toutes deux parcourir une tonne de services. Ils peuvent être agrégés ou décomposés au contraire. Peut être mis en cache, peut être modifié.
C'est-à-dire la demande http et la réponse http ont leur propre itinéraire. Et cela ne dépend ni de l'extrémité arrière, ni de l'extrémité avant. Je vous demande de porter une attention particulière à cela.
Les routes http ne sont pas statiques. Ils peuvent être très compliqués. Par exemple, si un équilibreur est intégré à l'infrastructure, il peut envoyer des demandes reçues à l'un des nœuds arrières. Dans le même temps, le backend lui-même peut mettre en œuvre sa propre stratégie de traitement des demandes. Certains d'entre eux iront directement aux microservices, certains seront traités par le serveur Web lui-même, certains seront ajoutés et transférés à quelqu'un d'autre, et certains seront émis à partir du cache, etc. Voilà comment fonctionne Internet. Rien de nouveau.
Et ici, il est important de comprendre - pourquoi avons-nous besoin de codes de réponse? Le fait est que tout le modèle décrit ci-dessus prend des décisions en fonction d'eux. C'est-à-dire ce sont des codes qui vous permettent de prendre des décisions d'infrastructure et de transport pendant le routage http.
Par exemple, si l'équilibreur rencontre un code de réponse du support 503, lors de l'envoi d'une demande, il peut prendre cela comme base pour considérer que le nœud est temporairement indisponible. Je note que la réponse avec le code 503 fournit un en-tête Retry-After. Après avoir reçu de l'en-tête l'intervalle de polling répété, l'équilibreur laissera le noeud seul pendant la période spécifiée et travaillera avec ceux disponibles. De plus, de telles stratégies sont mises en œuvre «prêtes à l'emploi» par les serveurs Web.
Un petit sujet hors sujet pour une meilleure compréhension - et si le nœud répondait 500? Que doit faire l'équilibreur? Passer à un autre? Et beaucoup répondront - bien sûr, tous les motifs 5xx pour désactiver un nœud. Et ils auront tort. Le code 500 est un code d'erreur inattendu. C'est-à-dire celui qui peut ne jamais se reproduire. Et surtout, le passage à un autre nœud peut ne rien changer. C'est-à-dire nous désactivons simplement les nœuds sans le moindre avantage.
Dans le cas de 500, les statistiques viennent à notre secours. Le serveur WEB local du nœud peut traduire le nœud lui-même en état indisponible avec un grand nombre de réponses 500. Dans ce cas, l'équilibreur contactant ce nœud recevra une réponse 503 et ne la touchera pas. Le résultat est le même, mais maintenant, cette solution est significative et élimine les «fausses» réponses.
Mais ce n'est pas tout. Dans cette situation, la surveillance permettra aux administrateurs de se connecter à la situation pour maintenir le nœud. C'est-à-dire nous obtenons non seulement la mise en œuvre d'un service hautement accessible, avec des équilibreurs, etc., mais aussi un processus de support efficace.
Et tout cela vous permet de créer des codes de réponse de serveur. Toute architecture d'application WEB doit commencer par la conception de la couche de transport. J'espère que cela ne fait aucun doute.
REPOS
Je vais poser une question rhétorique - qu'est-ce que c'est? Et que lui avez-vous répondu? Je ne donnerai pas de liens vers des preuves évidentes, mais ce n'est probablement pas tout à fait ce que c'est en fait :) C'est juste une idéologie, un style. Quelques considérations sur le sujet - la meilleure façon de communiquer avec le dos. Et pas seulement communiquer, mais communiquer dans l'infrastructure WEB. C'est-à-dire basé sur http. Avec tous ces «trucs utiles» dont j'ai parlé plus haut. Les décisions ultimes pour mettre en œuvre votre interface sont toujours à
vous .
Vous êtes-vous déjà demandé pourquoi un transport séparé pour REST n'a pas été inventé? Par exemple, pour websocket c'est le cas. Oui, cela commence également par http, mais ensuite, une fois la connexion établie, il s'agit généralement d'une chanson distincte. Pourquoi ne pas faire de même pour REST?
La réponse est simple - pourquoi? Il existe un beau protocole prêt à l'emploi et vérifié - http. Il évolue bien. Vous permet de mettre en œuvre des services complexes et hautement accessibles qui peuvent faire face à une lourde charge. Il suffit d'introduire quelques règles conceptuelles pour que les développeurs se comprennent.
D'ici suit une conclusion simple et évidente - tout ce qui est inhérent à http est inhérent à REST. Ce sont des entités inséparables. Il n'y a pas d'en-tête REST séparé, pas même un indice que REST est REST. Pour tout serveur REST, la demande est exactement la même que n'importe quel autre. C'est-à-dire REST est exactement ce que nous avons en tête.
Codes de réponse http REST
Parlons du code que votre serveur doit répondre à une demande REST? Personnellement, il me semble que de tout ce qui précède, la réponse est déjà évidente, car REST n'est pas différent de toute autre demande, il doit être soumis exactement aux mêmes règles. Le code de réponse fait partie intégrante de REST et doit être pertinent pour l'essence de la réponse. C'est-à-dire si l'objet n'a pas été trouvé par requête, c'est 404, si le client a fait une requête incorrecte 400, etc. Mais, le plus souvent, le débat ne s'arrête pas là. Je vais donc continuer.
Est-il possible de tout répondre avec le code 200? Et qui vous interdira? Veuillez ... le code 200 est le même code que les autres. Certes, la base de cette approche est une thèse très simple - mon système est parfait, il ne contient aucune erreur. Si vous êtes une personne capable de créer de tels systèmes - cela ne peut qu'être envié!
Mais très probablement ... elle n'est pas parfaite. Et des erreurs se produisent. Et il arrive qu'ils se produisent en raison de circonstances indépendantes de notre volonté. Et ici, une solution typique consiste à créer votre propre système de codage d'erreur. C'est mauvais? Oui, c'est mauvais. C'est super mauvais. Voyons pourquoi.
Et donc, en prenant le code 200 comme le seul vrai, nous prenons la responsabilité de développer toute la couche (couche critique) du système - la gestion des erreurs. C'est-à-dire le travail de nombreuses personnes pour développer cette couche est mis au rebut. Et la construction de son «vélo» commence. Mais ce méga-bâtiment est voué à l'échec.
Commençons par le code. Si nous voulons répondre aux 200 questions, nous devrons nous-mêmes gérer les erreurs. La méthode classique est d'essayer des constructions. Chaque segment de code que nous enveloppons avec du code supplémentaire. Les gestionnaires qui font quelque chose d'utile. Par exemple, ils ont mis quelque chose dans le journal. Quelque chose d'important. Cela localisera l'erreur. Et si l'erreur ne survenait pas là où elle était attendue? Ou si une erreur s'est produite dans le gestionnaire d'erreurs? C'est-à-dire cette stratégie au niveau du code ne fonctionne pas a priori. Et à la fin, l'interpréteur ou la plateforme traitera vos bugs. OS enfin. L'essence du bug est que vous ne l'attendez pas. Vous n'avez pas besoin de le cacher, vous devez le trouver et le réparer. Par conséquent, si REST répond à certaines demandes avec une erreur de 500, cela est
normal . Et en plus, c'est
ça .
Revenons à la question - pourquoi est-ce vrai? Parce que:
- Le code 500 est un jeton d'infrastructure basé sur lequel le nœud sur lequel le problème se produit peut être désactivé;
- Les codes 5xx sont ce qui est surveillé et si un tel code apparaît, tout système de surveillance vous en informera immédiatement. Et le service d'assistance à temps pourra se connecter à la solution du problème;
- Vous n'écrivez pas de code supplémentaire. Ne perdez pas un temps précieux à ce sujet. Ne compliquez pas l'architecture. Vous ne traitez pas de problèmes inhabituels pour vous - vous écrivez du code d'application. Ce qu'ils attendent de vous. Pour quoi payent-ils?
- Une trace qui tombe par erreur 500 sera beaucoup plus utile que vos tentatives pour la dépasser.
- Si la demande REST renvoie 500 codes, le front déjà au moment du traitement de la réponse saura par quel algorithme le traiter. De plus, l’essence de la question ne changera en rien, vous n’avez rien reçu de bon de 200 ou de 500. Mais de 500 vous avez reçu un profit - la prise de conscience qu’il s’agit d’une erreur INATTENDUE.
- Le code 500 sera accompagné d'une garantie. Peu importe à quel point vous avez écrit votre code. Ceci est votre point d'appui.
Séparément, je vais enfoncer un clou dans tout le «corps» du code 200:
7. Même si vous essayez très fort d'éviter d'autres codes de réponse du serveur autres que 200 à vos demandes, vous ne pouvez pas le faire. Tout serveur intermédiaire peut répondre à votre demande avec absolument n'importe quel code. Et vous DEVEZ traiter correctement une telle réponse.
Total, au niveau logique, la lutte pour le code 200 n'a pas de sens.
Revenons maintenant au niveau de l'infrastructure. Très souvent, j'entends l'opinion - le code 5xx n'est pas un niveau d'application, il ne peut pas être soutenu. Ahem, eh bien ... il y a une contradiction dans la déclaration elle-même. Vous pouvez donner. Mais ce code n'est pas un niveau d'application. C'est plus vrai. Pour comprendre cela, je propose d'examiner le cas:
Vous implémentez une passerelle. Vous avez plusieurs contrôleurs de domaine, chacun avec son propre canal de communication vers un certain service privé. Eh bien, par exemple, pour payer via VPN. Et il existe un canal de communication avec Internet. Vous recevez une demande d'opération avec une passerelle, mais ... le service n'est pas disponible.
Et alors, que devez-vous répondre? À qui? Il s'agit d'un problème d'infrastructure et, en particulier, la sauvegarde s'est heurtée à celui-ci. Bien sûr, vous devez répondre avec audace 503. Ces actions entraîneront le fait que le nœud sera désactivé par l'équilibreur pendant un certain temps. Dans le même temps, l'équilibreur, s'il est correctement configuré, sans rompre la connexion avec le client, enverra la demande à un autre nœud. Et ... le client final, avec un haut degré de probabilité, en a reçu 200. Et pas une description personnalisée de l'erreur, ce qui ne l'aidera en aucune façon.
Où et quel code utiliser
La question n'est pas simple. Il n'y a pas de réponse définitive à cela. Pour chaque système, une couche de transport est conçue et les codes qu'elle contient peuvent être spécifiques.
Il existe des normes acceptées. Ils peuvent être facilement trouvés et, encore une fois, je ne donnerai pas de preuves évidentes. Mais, je vais vous donner l'inévitable -
developer.mozilla.org/en/docs/Web/HTTP/StatusPourquoi lui? Le fait est que les gestionnaires de code peuvent se comporter différemment, selon l'implémentation et le contexte de «compréhension du code». Par exemple, les navigateurs ont une stratégie de mise en cache basée sur des codes de réponse. Et certains services ont leurs propres codes personnalisés. Par exemple, CloudFlare.
C'est-à-dire Pour prendre des décisions sur l'utilisation des codes, vous devez vous baser sur tous les éléments inclus dans la couche de transport, de votre code au verso au code sur le client. C'est le seul moyen de trouver les bonnes réponses. Je n'essaierai même pas de donner à tout le monde une pilule universelle ici.
Racines du mal
Ceci est le troisième projet que je viens de souffrir du code 200 dans REST. Il souffre. Il n'y a pas d'autre mot. Si vous lisez attentivement tout jusqu'à l'instant présent, vous comprenez déjà que dès que le projet commence à croître, il a besoin de développement des infrastructures, pour sa pérennité. Le code 200 tue toutes ces tentatives dans l'œuf. Et la première chose que vous devez faire est de briser les stéréotypes.
La racine du mal, il me semble, réside dans le fait que le code 500 est la première chose qu'un développeur web rencontre dans sa carrière professionnelle. On peut dire une blessure infantile. Et tous ses efforts se sont d'abord résumés à obtenir le code 200.
Soit dit en passant, pour une raison quelconque, au même stade, une opinion forte se développe que seules les réponses avec le code 200 peuvent être fournies avec un corps. Bien sûr, ce n'est pas le cas, et toute réponse peut «venir» avec n'importe quel code. Le code est un code. Le corps est le corps.
De plus, avec le développement du développeur, il doit gérer les bugs de sa propre application. Mais ..., il ne sait pas utiliser les logs. Impossible de configurer le serveur Web. Il étudie. Et ces très «grands» sont nés. Parce qu'ils sont à sa disposition et qu'il peut les faire rapidement. De plus, sur ce "grand" il monte de nouvelles roues, renforce le cadre, etc. Et ce grand devient son compagnon pendant une période suffisamment longue, jusqu'à ... jusqu'à ce qu'il ait des tâches vraiment complexes et multicomposantes. Et ici, comme on dit - l'entrée au supermarché avec le "grand" et le roller est interdite.
PS: L'auteur de l'article mentionné l'a restauré à partir des versions préliminaires -
habr.com/en/post/440382 , afin que vous puissiez également vous familiariser avec celui-ci.
PPS: J'ai essayé d'énoncer toutes les facettes de la nécessité d'utiliser des codes de réponse pertinents dans REST. Je ne répondrai pas aux commentaires, veuillez me comprendre correctement. Je vais les lire avec beaucoup d'attention, mais je n'ai rien à ajouter. Merci beaucoup d'avoir été assez patient pour lire l'article!