In diesem Abschnitt sprechen wir über Anfragen. In Nginx beziehen wir uns auf http-Anfragen. Die spezifische Datenstruktur in Nginx ist ngx_http_request_t. ngx_http_request_t ist eine Kapselung einer http-Anfrage. Wir wissen, dass eine HTTP-Anfrage eine Anforderungszeile, einen Anforderungsheader, einen Anforderungstext, eine Antwortzeile, einen Antwortheader und einen Antworttext umfasst.
http-Anfrage ist ein typisches Netzwerkprotokoll vom Typ Anfrage-Antwort, und http ist ein Dateiprotokoll. Daher analysieren wir die Anfragezeile und den Anfrageheader und geben die Antwortzeile und den Antwortheader häufig Zeile für Zeile aus mit. Wenn wir selbst einen HTTP-Server schreiben, sendet der Client normalerweise nach dem Herstellen einer Verbindung eine Anfrage. Dann lesen wir eine Datenzeile und analysieren die in der Anforderungszeile enthaltenen Methoden-, URI- und http_version-Informationen. Verarbeiten Sie dann die Anforderungsheader Zeile für Zeile und bestimmen Sie anhand der Anforderungsmethode und der Anforderungsheaderinformationen, ob ein Anforderungstext und die Länge des Anforderungstexts vorhanden sind, und lesen Sie dann den Anforderungstext. Nachdem wir die Anfrage erhalten haben, verarbeiten wir die Anfrage, um die auszugebenden Daten zu generieren, und generieren dann die Antwortzeile, den Antwortheader und den Antworttext. Nachdem die Antwort an den Client gesendet wurde, wird eine vollständige Anfrage verarbeitet. Dies ist natürlich die einfachste Webserver-Verarbeitungsmethode. Nginx führt dies jedoch auch aus, es gibt jedoch einige kleine Unterschiede. Beispielsweise beginnt die Anforderungsverarbeitung, wenn der Anforderungsheader gelesen wird. Nginx verwendet ngx_http_request_t, um Daten im Zusammenhang mit Analyseanforderungen und Ausgabeantworten zu speichern.
Lassen Sie uns als Nächstes kurz darüber sprechen, wie Nginx eine vollständige Anfrage verarbeitet. Für nginx beginnt eine Anfrage bei ngx_http_init_request. In dieser Funktion wird das Leseereignis auf ngx_http_process_request_line gesetzt. Das heißt, das nächste Netzwerkereignis wird von ngx_http_process_request_line ausgeführt. Aus dem Funktionsnamen von ngx_http_process_request_line können wir ersehen, dass es sich hierbei um die Verarbeitung der Anforderungszeile handelt. Wie bereits erwähnt, besteht das erste, was bei der Verarbeitung einer Anforderung zu tun ist, darin, die Anforderungszeile zu verarbeiten. Anforderungsdaten über ngx_http_read_request_header lesen. Anschließend wird die Funktion ngx_http_parse_request_line aufgerufen, um die Anforderungszeile zu analysieren. Um die Effizienz zu verbessern, verwendet Nginx eine Zustandsmaschine zum Parsen der Anforderungszeile. Beim Vergleich von Methoden wird kein direkter String-Vergleich durchgeführt. Stattdessen werden vier Zeichen in eine Ganzzahl umgewandelt und dann einmal verglichen, um die Anzahl der CPU-Anweisungen zu reduzieren . Das wurde schon einmal gesagt. Viele Leute wissen vielleicht, dass eine Anforderungszeile die angeforderte Methode, den URI und die Version enthält, aber sie wissen nicht, dass die Anforderungszeile auch einen Host enthalten kann. Beispielsweise ist eine Anfrage wie GET http://www.taobao.com/uri HTTP/1.0 ebenfalls zulässig, und der Host ist www.taobao.com. Zu diesem Zeitpunkt ignoriert Nginx das Hostfeld im Anfrageheader und use Verwenden Sie dies in der Anforderungszeile, um den virtuellen Host zu finden. Darüber hinaus werden für die http0.9-Version Anforderungsheader nicht unterstützt, sodass hier eine besondere Behandlung erforderlich ist. Daher lautet die Protokollversion beim späteren Parsen des Anforderungsheaders 1.0 oder 1.1. Die aus der gesamten Anforderungszeile analysierten Parameter werden in der Struktur ngx_http_request_t gespeichert.
Nach dem Parsen der Anforderungszeile setzt Nginx den Handler des Leseereignisses auf ngx_http_process_request_headers, und nachfolgende Anforderungen werden dann in ngx_http_process_request_headers gelesen und analysiert. Die Funktion ngx_http_process_request_headers wird zum Lesen von Anforderungsheadern verwendet. Sie ruft weiterhin ngx_http_read_request_header auf, um die Anforderungsheader zu lesen, und ruft ngx_http_parse_header_line auf, um eine Zeile von Anforderungsheadern zu analysieren. Die analysierten Anforderungsheader werden im Feld headers_in von ngx_http_request_t gespeichert .headers_in ist eine verknüpfte Listenstruktur, in der alle Anforderungsheader gespeichert werden. Einige Anforderungen in HTTP erfordern eine spezielle Verarbeitung. Diese Anforderungsheader und Anforderungsverarbeitungsfunktionen werden in einer Zuordnungstabelle gespeichert, nämlich ngx_http_headers_in. Wenn ein Anforderungsheader analysiert wird, wird er zuerst in diesem Hash gespeichert Tabelle, und falls gefunden, rufen Sie die entsprechende Verarbeitungsfunktion auf, um den Anforderungsheader zu verarbeiten. Beispiel: Die Verarbeitungsfunktion des Host-Headers lautet ngx_http_process_host.
Wenn Nginx zwei Wagenrückläufe und Zeilenvorschübe analysiert, zeigt dies das Ende des Anforderungsheaders an. Zu diesem Zeitpunkt wird ngx_http_process_request aufgerufen, um die Anforderung zu verarbeiten. ngx_http_process_request setzt die Lese- und Schreibereignisverarbeitungsfunktion der aktuellen Verbindung auf ngx_http_request_handler und ruft dann ngx_http_handler auf, um tatsächlich mit der Verarbeitung einer vollständigen http-Anfrage zu beginnen. Es kann hier seltsam sein. Die Lese- und Schreibereignisverarbeitungsfunktionen sind beide ngx_http_request_handler. Tatsächlich wird in dieser Funktion der read_event_handler bzw. write_event_handler in ngx_http_request_t aufgerufen, je nachdem, ob das aktuelle Ereignis ein Leseereignis oder ein Schreibereignis ist. Da unser Anforderungsheader zu diesem Zeitpunkt gelesen wurde, liest Nginx, wie bereits erwähnt, nicht zuerst den Anforderungstext. Daher setzen wir hier read_event_handler auf ngx_http_block_reading, dh es werden keine Daten gelesen. Wie gerade erwähnt, liegt der eigentliche Beginn der Datenverarbeitung in der Funktion ngx_http_handler. Diese Funktion setzt write_event_handler auf ngx_http_core_run_phases und führt die Funktion ngx_http_core_run_phases aus. Die Funktion ngx_http_core_run_phases führt eine mehrstufige Anforderungsverarbeitung durch. Nginx unterteilt die Verarbeitung einer http-Anfrage in mehrere Phasen. Anschließend führt diese Funktion diese Phasen aus, um Daten zu generieren. Da ngx_http_core_run_phases schließlich Daten generiert, ist es für uns leicht zu verstehen, warum die Schreibereignisverarbeitungsfunktion auf ngx_http_core_run_phases eingestellt ist. Hier erkläre ich kurz die Aufruflogik der Funktion. Wir müssen verstehen, dass ngx_http_core_run_phases letztendlich aufgerufen wird, um die Anfrage zu verarbeiten. Der generierte Antwortheader wird in den headers_out von ngx_http_request_t eingefügt. . Nginx verarbeitet die Anforderung in verschiedenen Phasen und ruft schließlich den Filter auf, um die Daten zu filtern und zu verarbeiten, z. B. verkürzte Übertragung, GZIP-Komprimierung usw. Der Filter umfasst hier den Header Filter und Textfilter verarbeiten den Antwortheader oder den Antworttext. Filter ist eine verknüpfte Listenstruktur mit Header-Filter und Body-Filter. Zuerst werden alle Filter im Header-Filter und dann alle Filter im Body-Filter ausgeführt. Der letzte Filter im Header-Filter, nämlich ngx_http_header_filter, durchläuft alle Antwortheader, die ausgegeben werden müssen, und ruft dann ngx_http_write_filter zur Ausgabe auf. ngx_http_write_filter ist der Körper Der letzte im Filter, also die ersten Körperinformationen von Nginx, ruft nach einer Reihe von Körperfiltern schließlich ngx_http_write_filter zur Ausgabe auf (es gibt ein Bild zur Veranschaulichung).
Hier ist zu beachten, dass Nginx den gesamten Anforderungsheader in einen Puffer legt. Die Größe dieses Puffers wird über das Konfigurationselement client_header_buffer_size festgelegt, wenn der Anforderungsheader des Benutzers zu groß ist und dieser Puffer nicht hineinpasst , dann weist nginx einen neuen größeren Puffer zu, um den Anforderungsheader zu speichern. Diese große Puffergruppe kann beispielsweise durch die Konfiguration von 4 8-KByte-Puffer festgelegt werden. Beachten Sie, dass zur Wahrung der Integrität der Anforderungszeile oder des Headers eine vollständige Anforderungszeile oder ein vollständiger Header in einem kontinuierlichen Speicher abgelegt werden muss. Daher wird eine vollständige Anforderungszeile oder ein vollständiger Header nur in einem Puffer gespeichert. Auf diese Weise wird ein 414-Fehler zurückgegeben, wenn die Anforderungszeile größer als die Größe eines Puffers ist, und wenn die Größe eines Anforderungsheaders größer als die Puffergröße ist, wird ein 400-Fehler zurückgegeben. Nachdem wir die Werte dieser Parameter und die tatsächlichen Praktiken von Nginx im Anwendungsszenario verstanden haben, müssen wir diese Parameter entsprechend den tatsächlichen Anforderungen anpassen, um unser Programm zu optimieren.
Verarbeitungsflussdiagramm:
Das Obige ist der Lebenszyklus einer http-Anfrage in Nginx. Schauen wir uns einige Konzepte im Zusammenhang mit Anfragen an.
Das Obige stellt die Anfrage in Nginx vor, einschließlich des relevanten Inhalts. Ich hoffe, dass es für Freunde hilfreich ist, die sich für PHP-Tutorials interessieren.