
Ich wollte diesen Artikel schon lange schreiben. Ich fragte mich immer wieder, welche Seite ich besser betreten sollte. Aber plötzlich, kürzlich, erschien ein ähnlicher Artikel über Habré, der einen Sturm in einem Glas verursachte. Was mich am meisten überraschte, war die Tatsache, dass der Artikel in Minuspunkten gefahren wurde, obwohl er nicht einmal etwas deklarierte, sondern die Frage nach der Verwendung von Webserver-Antwortcodes in REST aufwirft. Die Debatte wurde heiß. Und die Apotheose war, dass der Artikel in den Entwurf ging ... Kilobyte an Kommentaren, Meinungen usw. einfach verschwunden. Viele wurden Karmo-Opfer, denken Sie umsonst :)
Im Allgemeinen war es das Schicksal dieses Artikels, das mich dazu veranlasste, diesen Artikel zu schreiben. Und ich hoffe wirklich, dass es nützlich sein und viel klarstellen wird.
Ich warne Sie, alles, was unten geschrieben steht, ist eine echte Erfahrung, kein kognitiver Balanceakt. Und so fuhren sie.
HTTP
Das erste, was zu tun ist, ist, die Schichten sehr klar zu trennen. Die Transportschicht ist http. Nun, eigentlich REST. Dies ist eine grundlegend wichtige Sache, um alles und „sich selbst“ darin zu akzeptieren. Lassen Sie uns zuerst nur über http sprechen.
Ich habe den Begriff "Transportschicht" verwendet. Und ich habe keine Reservierung gemacht. Die Sache ist, dass http selbst die Funktionen des Transports von Anforderungen zum Server und von Inhalten zum Client implementiert, unabhängig von tcp / ip. Ja, es basiert auf TCP / IP. Und es scheint notwendig, es als seinen Transport zu betrachten. Aber nein. Und hier ist der Grund: Socket-Verbindungen sind nicht direkt, d. H. Dies ist keine Client-Server-Verbindung. Sowohl die http-Anfrage als auch die http-Antwort können eine Menge Dienste durchlaufen. Sie können im Gegenteil aggregiert oder zerlegt werden. Kann zwischengespeichert werden, kann geändert werden.
Das heißt, Sowohl die http-Anfrage als auch die http-Antwort haben ihre eigene Route. Und es kommt weder auf das Ende hinten noch auf das Ende vorne an. Ich bitte Sie, dies besonders zu beachten.
Die http-Routen sind nicht statisch. Sie können sehr kompliziert sein. Wenn beispielsweise ein Balancer in die Infrastruktur integriert ist, kann er empfangene Anforderungen an jeden der Backknoten senden. Gleichzeitig kann das Backend selbst eine eigene Strategie für die Arbeit mit Anforderungen implementieren. Einige von ihnen werden direkt an Microservices weitergeleitet, andere werden vom Webserver selbst verarbeitet, andere werden hinzugefügt und an eine andere Person übertragen, andere werden aus dem Cache ausgegeben usw. So funktioniert das Internet. Nichts Neues.
Und hier ist es wichtig zu verstehen - warum brauchen wir Antwortcodes? Die Sache ist, dass das gesamte oben beschriebene Modell Entscheidungen basierend auf ihnen trifft. Das heißt, Dies sind Codes, mit denen Sie während des http-Routings Infrastruktur- und Transportentscheidungen treffen können.
Wenn der Balancer beispielsweise beim Senden einer Anforderung auf einen Antwortcode aus der Sicherung 503 stößt, kann er dies als Grund für die Annahme nehmen, dass der Knoten vorübergehend nicht verfügbar ist. Ich stelle fest, dass die Antwort mit Code 503 einen Retry-After-Header enthält. Nachdem der Balancer das Intervall für die wiederholte Abfrage vom Header erhalten hat, lässt er den Knoten für den angegebenen Zeitraum in Ruhe und arbeitet mit den verfügbaren. Darüber hinaus werden solche Strategien von Webservern „out of the box“ implementiert.
Ein kleines offtopic für tiefes Verständnis - was ist, wenn der Knoten 500 geantwortet hat? Was soll der Balancer tun? Zu einem anderen wechseln? Und viele werden antworten - natürlich alle 5xx Gründe für die Deaktivierung eines Knotens. Und sie werden falsch liegen. Code 500 ist ein unerwarteter Fehlercode. Das heißt, eine, die nie wieder passieren kann. Und am wichtigsten ist, dass das Wechseln zu einem anderen Knoten möglicherweise nichts ändert. Das heißt, Wir deaktivieren einfach Knoten ohne den geringsten Vorteil.
Bei 500 helfen uns Statistiken. Der lokale WEB-Server des Knotens kann den Knoten selbst mit einer großen Anzahl von 500 Antworten in den Nichtverfügbarkeitsstatus übersetzen. In diesem Fall erhält der Balancer, der diesen Knoten kontaktiert, eine 503-Antwort und berührt ihn nicht. Das Ergebnis ist das gleiche, aber jetzt ist diese Lösung sinnvoll und eliminiert „falsche“ Antworten.
Das ist aber noch nicht alles. In dieser Situation ermöglicht die Überwachung Administratoren, eine Verbindung zur Situation herzustellen, um den Knoten zu warten. Das heißt, Wir erhalten nicht nur die Implementierung eines leicht zugänglichen Dienstes mit Balancern usw., sondern auch einen effektiven Supportprozess.
Auf diese Weise können Sie Server-Antwortcodes erstellen. Jede WEB-Anwendungsarchitektur sollte mit dem Entwurf der Transportschicht beginnen. Ich hoffe, daran besteht kein Zweifel.
RUHE
Ich werde eine rhetorische Frage stellen - was ist das? Und was hast du ihm geantwortet? Ich werde keine Links zu offensichtlichen Beweisen geben, aber höchstwahrscheinlich ist es nicht ganz das, was es tatsächlich ist :) Dies ist nur eine Ideologie, ein Stil. Einige Überlegungen zum Thema - wie man am besten mit dem Rücken kommuniziert. Und nicht nur kommunizieren, sondern in der WEB-Infrastruktur kommunizieren. Das heißt, basierend auf http. Mit all den "nützlichen Sachen", über die ich oben geschrieben habe. Die endgültigen Entscheidungen zur Implementierung Ihrer Benutzeroberfläche liegen immer bei
Ihnen .
Haben Sie sich jemals gefragt, warum ein separater Transport für REST nicht erfunden wurde? Zum Beispiel für Websocket ist es. Ja, es beginnt auch mit http, aber nachdem die Verbindung hergestellt wurde, ist dies im Allgemeinen ein separates Lied. Warum nicht dasselbe für REST tun?
Die Antwort ist einfach - warum? Es gibt ein schönes, vorgefertigtes, verifiziertes Protokoll - http. Es skaliert gut. Ermöglicht die Implementierung komplexer, leicht zugänglicher Dienste, die eine hohe Last bewältigen können. Alles, was benötigt wird, ist die Einführung einiger konzeptioneller Regeln, damit sich die Entwickler verstehen.
Daraus folgt eine einfache, offensichtliche Schlussfolgerung: Alles, was http innewohnt, ist REST inhärent. Dies sind untrennbare Einheiten. Es gibt keinen separaten REST-Header, nicht einmal einen Hinweis darauf, dass REST REST ist. Für jeden REST-Server ist die Anforderung genau dieselbe wie für jeden anderen. Das heißt, REST ist genau das, was wir uns vorgestellt haben.
REST http-Antwortcodes
Lassen Sie uns darüber sprechen, welchen Code Ihr Server auf eine REST-Anfrage antworten soll. Persönlich scheint mir, dass aus all dem die Antwort bereits offensichtlich ist, weil REST unterscheidet sich nicht von anderen Anforderungen, es muss genau den gleichen Regeln unterliegen. Der Antwortcode ist ein integraler Bestandteil von REST und sollte für das Wesentliche der Antwort relevant sein. Das heißt, Wenn das Objekt nicht auf Anfrage gefunden wurde, ist es 404, wenn der Client eine falsche Anfrage 400 usw. gestellt hat. Meistens endet die Debatte dort jedoch nicht. Deshalb werde ich weitermachen.
Kann man alles mit Code 200 beantworten? Und wer wird es dir verbieten? Bitte ... Code 200 ist der gleiche Code wie die anderen. Die Grundlage dieses Ansatzes ist zwar eine sehr einfache These - mein System ist perfekt, es hat keine Fehler. Wenn Sie eine Person sind, die solche Systeme erstellen kann, kann dies nur beneidet werden!
Aber höchstwahrscheinlich ... ist sie nicht perfekt. Und Fehler passieren. Und es kommt vor, dass sie aufgrund von Umständen auftreten, die außerhalb unserer Kontrolle liegen. Und hier besteht eine typische Lösung darin, ein eigenes Fehlercodierungssystem zu erstellen. Das ist schlecht? Ja, das ist schlecht. Das ist super schlecht. Lassen Sie uns herausfinden, warum.
Ausgehend von Code 200 übernehmen wir die Verantwortung für die Entwicklung der gesamten Schicht (kritische Schicht) des Systems - Fehlerbehandlung. Das heißt, Die Arbeit vieler Menschen, diese Schicht zu entwickeln, wird in Schrott gesteckt. Und der Bau seines „Fahrrads“ beginnt. Aber dieses Mega-Gebäude ist zum Scheitern verurteilt.
Beginnen wir mit dem Code. Wenn wir alle 200 beantworten wollen, müssen wir die Fehler selbst behandeln. Die klassische Methode sind Try-Konstrukte. Jedes Codesegment wird mit zusätzlichem Code umbrochen. Handler, die etwas Nützliches tun. Zum Beispiel haben sie etwas in das Protokoll aufgenommen. Etwas Wichtiges. Dadurch wird der Fehler lokalisiert. Und wenn der Fehler nicht dort auftrat, wo er erwartet wurde? Oder wenn im Fehlerhandler ein Fehler aufgetreten ist? Das heißt, Diese Strategie auf Codeebene funktioniert nicht von vornherein. Und am Ende wird der Interpreter oder die Plattform Ihre Fehler verarbeiten. Betriebssystem endlich. Das Wesentliche des Fehlers ist, dass Sie nicht darauf warten. Sie müssen es nicht verstecken, Sie müssen es finden und reparieren. Wenn REST auf einige Anforderungen mit einem Fehler von 500 antwortet, ist dies
normal . Und was mehr ist,
richtig .
Kommen wir zurück zu der Frage: Warum ist das richtig? Weil:
- Code 500 ist ein Infrastruktur-Token, auf dessen Grundlage der Knoten, auf dem das Problem auftritt, deaktiviert werden kann.
- 5xx-Codes werden überwacht, und wenn ein solcher Code auftritt, werden Sie von jedem Überwachungssystem unverzüglich darüber informiert. Und der Support-Service kann sich rechtzeitig mit der Lösung des Problems verbinden.
- Sie schreiben keinen zusätzlichen Code. Verschwenden Sie keine kostbare Zeit damit. Komplizieren Sie die Architektur nicht. Sie beschäftigen sich nicht mit für Sie ungewöhnlichen Problemen - Sie schreiben Anwendungscode. Was sie von dir wollen. Wofür bezahlen sie?
- Eine Spur, die versehentlich 500 herausfällt, ist viel nützlicher als Ihre Versuche, sie zu übertreffen.
- Wenn die REST-Anforderung 500 Code zurückgibt, weiß die Front bereits zum Zeitpunkt der Verarbeitung der Antwort, durch welchen Algorithmus sie verarbeitet werden soll. Darüber hinaus wird sich das Wesentliche in keiner Weise ändern, Sie haben sowohl von 200 als auch von 500 nichts Sinnvolles erhalten. Aber von 500 haben Sie einen Gewinn erhalten - die Erkenntnis, dass dies ein UNERWARTETER Fehler ist.
- Code 500 wird mit einer Garantie geliefert. Egal wie schlecht oder gut Sie Ihren Code geschrieben haben. Das ist dein Drehpunkt.
Separat werde ich einen Nagel in den gesamten „Körper“ von Code 200 hämmern:
7. Selbst wenn Sie sich sehr bemühen, andere Antwortcodes vom Server als 200 auf Ihre Anforderungen zu vermeiden, können Sie dies nicht tun. Jeder zwischengeschaltete Server kann auf Ihre Anfrage mit absolut jedem Code antworten. Und Sie sollten eine solche Antwort richtig verarbeiten.
Insgesamt ist der Kampf um Code 200 auf logischer Ebene bedeutungslos.
Kommen wir nun zur Infrastrukturebene zurück. Sehr oft höre ich die Meinung - der 5xx-Code ist keine Anwendungsebene, er kann nicht unterstützt werden. Ähm, na ja ... es gibt einen Widerspruch in der Aussage selbst. Du kannst geben. Dieser Code ist jedoch keine Anwendungsebene. Das stimmt mehr. Um dies zu verstehen, schlage ich vor, den Fall zu betrachten:
Sie implementieren ein Gateway. Sie haben mehrere DCs, von denen jeder einen eigenen Kommunikationskanal zu einem bestimmten privaten Dienst hat. Zum Beispiel per VPN bezahlen. Und es gibt einen Kommunikationskanal mit dem Internet. Sie erhalten eine Anforderung für einen Vorgang mit einem Gateway, aber ... der Dienst ist nicht verfügbar.
Und was solltest du antworten? Zu wem? Dies ist ein Infrastrukturproblem, auf das insbesondere die Sicherung gestoßen ist. Natürlich müssen Sie 503 kühn beantworten. Diese Aktionen führen dazu, dass der Knoten für einige Zeit vom Balancer deaktiviert wird. Gleichzeitig sendet der Balancer bei korrekter Konfiguration die Anforderung an einen anderen Knoten, ohne die Verbindung zum Client zu unterbrechen. Und ... der Endkunde erhielt mit hoher Wahrscheinlichkeit 200. Und keine benutzerdefinierte Beschreibung des Fehlers, die ihm in keiner Weise helfen wird.
Wo und welcher Code verwendet werden soll
Die Frage ist nicht einfach. Es gibt keine eindeutige Antwort darauf. Für jedes System wird eine Transportschicht entworfen, und die darin enthaltenen Codes können spezifisch sein.
Es gibt akzeptierte Standards. Sie sind leicht zu finden, und ich werde auch hier keine offensichtlichen Beweise liefern. Aber ich werde Ihnen den nicht offensichtlichen geben -
developer.mozilla.org/en/docs/Web/HTTP/StatusWarum er? Die Sache ist, dass sich Code-Handler je nach Implementierung und Kontext des „Verstehens des Codes“ unterschiedlich verhalten können. Beispielsweise haben Browser eine Caching-Strategie, die auf Antwortcodes basiert. Einige Dienste haben ihre eigenen, benutzerdefinierten Codes. Zum Beispiel CloudFlare.
Das heißt, Wenn Sie Entscheidungen über die Verwendung von Codes treffen, müssen Sie sich auf alle Elemente stützen, die in der Transportschicht enthalten sind, von Ihrem Code auf der Rückseite bis zum Code auf dem Client. Nur so finden Sie die richtigen Antworten. Ich werde hier nicht einmal versuchen, jedem eine universelle Pille zu geben.
Wurzeln des Bösen
Dies ist das dritte Projekt, bei dem ich unter Code 200 in REST leide. Es leidet. Es gibt kein anderes Wort. Wenn Sie alles bis zum aktuellen Moment sorgfältig lesen, verstehen Sie bereits, dass das Projekt, sobald es zu wachsen beginnt, einen Bedarf an Infrastrukturentwicklung und Nachhaltigkeit hat. Code 200 tötet alle diese Versuche im Keim. Und das erste, was Sie tun müssen, ist Stereotypen zu brechen.
Die Wurzel des Bösen scheint mir in der Tatsache zu liegen, dass der Code 500 das erste ist, auf das ein Webentwickler in seiner beruflichen Laufbahn stößt. Es kann eine Kindheitsverletzung gesagt werden. Und alle seine Bemühungen beschränkten sich zunächst darauf, Code 200 zu erhalten.
Übrigens entwickelt sich aus irgendeinem Grund im gleichen Stadium eine starke Meinung, dass nur Antworten mit Code 200 mit einem Körper geliefert werden können. Dies ist natürlich nicht der Fall, und jede Antwort kann mit einem beliebigen Code „kommen“. Code ist ein Code. Der Körper ist der Körper.
Darüber hinaus muss er mit der Entwicklung des Entwicklers die Fehler seiner eigenen Anwendung verwalten. Aber ... er weiß nicht, wie man Protokolle verwendet. Webserver kann nicht konfiguriert werden. Er lernt. Und diese sehr „Großen“ werden geboren. Weil sie ihm zur Verfügung stehen und er sie schnell herstellen kann. Außerdem montiert er auf diesem "großen" neue Räder, stärkt den Rahmen usw. Und dieser Große wird für einen ausreichend langen Zeitraum sein Begleiter, bis ... bis er wirklich komplexe Mehrkomponentenaufgaben hat. Und hier, wie sie sagen - der Eintritt in den Supermarkt mit dem "großen" und Rollschuhlaufen ist verboten.
PS: Der Autor des genannten Artikels hat ihn aus den Entwürfen wiederhergestellt -
habr.com/de/post/440382 , damit Sie sich auch damit vertraut machen können.
PPS: Ich habe versucht, alle Facetten der Notwendigkeit darzulegen, relevante Antwortcodes in REST zu verwenden. Ich werde nicht auf Kommentare antworten, bitte verstehe mich richtig. Ich werde sie mit großer Aufmerksamkeit lesen, aber ich habe nichts hinzuzufügen. Vielen Dank, dass Sie geduldig genug sind, um den Artikel zu lesen!