Aujourd'hui, nous parlons de requête. Dans Nginx, nous faisons référence à la requête http. La structure de données spécifique dans Nginx est ngx_http_request_t. ngx_http_request_t est une encapsulation d'une requête http. Nous savons qu'une requête http comprend une ligne de requête, un en-tête de requête, un corps de requête, une ligne de réponse, un en-tête de réponse et un corps de réponse.
La requête http est un protocole réseau typique de type requête-réponse, et http est un protocole texte, nous analysons donc la ligne de requête et l'en-tête de requête, et générons la ligne de réponse et l'en-tête de réponse, souvent ligne par ligne. avec. (Apprentissage recommandé : Utilisation de Nginx)
Si nous écrivons nous-mêmes un serveur http, généralement après l'établissement d'une connexion, le client enverra une requête. Ensuite, nous lisons une ligne de données et analysons les informations de méthode, d'uri et de version http contenues dans la ligne de requête.
Traitez ensuite les en-têtes de requête ligne par ligne et déterminez s'il existe un corps de requête et la longueur du corps de requête en fonction de la méthode de requête et des informations d'en-tête de requête, puis lisez le corps de la requête.
Après avoir reçu la demande, nous traitons la demande pour générer les données qui doivent être générées, puis générons la ligne de réponse, l'en-tête de réponse et le corps de la réponse.
Après l'envoi de la réponse au client, une demande complète est traitée. Bien sûr, il s'agit de la méthode de traitement du serveur Web la plus simple. En fait, Nginx le fait également, avec quelques différences mineures. Par exemple, lorsque l'en-tête de la requête est lu, le traitement de la requête commence. Nginx utilise ngx_http_request_t pour enregistrer les données liées à l'analyse des requêtes et aux réponses de sortie.
Ensuite, parlons brièvement de la façon dont Nginx gère une requête complète. Pour Nginx, une requête démarre à partir de ngx_http_init_request. Dans cette fonction, l'événement de lecture est défini sur ngx_http_process_request_line.
D'après le nom de la fonction ngx_http_process_request_line, nous pouvons voir qu'il s'agit de traiter la ligne de requête. Comme mentionné précédemment, la première chose à faire pour traiter la requête est de traiter la ligne de requête.
Lisez les données de la demande via ngx_http_read_request_header. La fonction ngx_http_parse_request_line est ensuite appelée pour analyser la ligne de requête. Afin d'améliorer l'efficacité, Nginx utilise une machine à états pour analyser la ligne de requête, lors de la comparaison des méthodes, il n'utilise pas directement la comparaison de chaînes, mais convertit quatre caractères en un entier, puis le compare une fois pour réduire le nombre d'instructions CPU. . Cela a déjà été dit.
Beaucoup de gens savent peut-être qu'une ligne de requête contient la méthode de requête, l'uri et la version, mais ils ne savent pas que la ligne de requête peut également contenir l'hôte. Par exemple, une requête telle que GET http://www.taobao.com/uri HTTP/1.0 est également légale et l'hôte est www.taobao.com. À ce stade, Nginx ignorera le champ hôte dans l'en-tête de la requête. et utilisez Utilisez ceci dans la ligne de requête pour trouver l'hôte virtuel.
De plus, pour la version http0.9, les en-têtes de requête ne sont pas pris en charge, un traitement spécial est donc requis ici. Par conséquent, lors de l’analyse ultérieure de l’en-tête de la requête, la version du protocole sera 1.0 ou 1.1. Les paramètres analysés à partir de toute la ligne de requête seront enregistrés dans la structure ngx_http_request_t.
Après avoir analysé la ligne de requête, Nginx définira le gestionnaire de l'événement de lecture sur ngx_http_process_request_headers, puis les requêtes suivantes seront lues et analysées dans ngx_http_process_request_headers.
La fonction ngx_http_process_request_headers est utilisée pour lire les en-têtes de requête, tout comme la ligne de requête, elle appelle toujours ngx_http_read_request_header pour lire les en-têtes de requête, et appelle ngx_http_parse_header_line pour analyser une ligne d'en-têtes de requête. dans le domaine headers_in de ngx_http_request_t , headers_in est une structure de liste chaînée qui enregistre tous les en-têtes de requête.
Certaines requêtes HTTP nécessitent un traitement spécial. Ces en-têtes de requête et fonctions de traitement de requête sont stockés dans une table de mappage, à savoir ngx_http_headers_in. Lors de l'initialisation, une table de hachage sera générée lorsqu'une requête est analysée. en-tête, il recherchera d'abord dans la table de hachage. Si elle est trouvée, la fonction de traitement correspondante sera appelée pour traiter l'en-tête de la requête. Par exemple : la fonction de traitement de l'en-tête Host est ngx_http_process_host.
Lorsque Nginx analyse deux retours chariot et sauts de ligne, il indique la fin de l'en-tête de la requête. À ce moment, ngx_http_process_request sera appelé pour traiter la requête.
ngx_http_process_request définira la fonction de gestionnaire d'événements de lecture et d'écriture de la connexion actuelle sur ngx_http_request_handler, puis appellera ngx_http_handler pour commencer réellement à traiter une requête http complète.
Cela peut paraître étrange. Les fonctions de traitement des événements de lecture et d'écriture sont toutes deux ngx_http_request_handler. En fait, dans cette fonction, le read_event_handler ou write_event_handler dans ngx_http_request_t sera appelé respectivement selon que l'événement en cours est un événement de lecture ou. un événement d'écriture.
Puisque notre en-tête de requête a été lu à ce moment-là, comme mentionné précédemment, l'approche de Nginx n'est pas de lire le corps de la requête en premier, nous définissons donc ici read_event_handler sur ngx_http_block_reading, c'est-à-dire qu'aucune donnée n'est lue.
Comme mentionné tout à l'heure, le véritable début du traitement des données se trouve dans la fonction ngx_http_handler. Cette fonction définira write_event_handler sur ngx_http_core_run_phases et exécutera la fonction ngx_http_core_run_phases.
ngx_http_core_run_phases Cette fonction effectuera un traitement de requête en plusieurs étapes. Nginx divise le traitement d'une requête http en plusieurs étapes, puis cette fonction exécutera ces étapes pour générer des données.
Étant donné que ngx_http_core_run_phases finira par générer des données, il nous est facile de comprendre pourquoi la fonction de traitement des événements d'écriture est définie sur ngx_http_core_run_phases.
Ici, j'explique brièvement la logique d'appel de la fonction. Nous devons comprendre que ngx_http_core_run_phases est finalement appelé pour traiter la requête. L'en-tête de réponse généré sera placé dans le headers_out de ngx_http_request_t. dans Parlons-en dans le processus de traitement des demandes. Différentes étapes de Nginx traiteront la requête et appelleront enfin un filtre pour filtrer les données et traiter les données, comme la transmission tronquée, la compression gzip, etc.
Le filtre comprend ici un filtre d'en-tête et un filtre de corps, qui traitent l'en-tête ou le corps de la réponse. Le filtre est une structure de liste chaînée, avec respectivement un filtre d'en-tête et un filtre de corps. Tous les filtres du filtre d'en-tête sont exécutés en premier, puis tous les filtres du filtre de corps sont exécutés.
Le dernier filtre du filtre d'en-tête est ngx_http_header_filter. Ce filtre traversera tous les en-têtes de réponse qui doivent être générés dans une mémoire continue, puis appellera ngx_http_write_filter pour la sortie.
ngx_http_write_filter est le dernier du filtre corporel, donc les premières informations corporelles de Nginx, après avoir traversé une série de filtres corporels, appelleront finalement ngx_http_write_filter pour la sortie (il y a une image pour illustrer).
Ce qu'il convient de noter ici, c'est que Nginx mettra l'intégralité de l'en-tête de requête dans un tampon. La taille de ce tampon est définie via l'élément de configuration client_header_buffer_size si l'en-tête de requête de l'utilisateur est trop grand et que ce tampon ne peut pas tenir. , alors Nginx réattribuera un nouveau tampon plus grand pour contenir l'en-tête de requête. Ce grand tampon peut être défini via large_client_header_buffers Le groupe de tampons large_buffer, tel que la configuration de 48 Ko, signifie que quatre tampons de 8 Ko sont disponibles.
Notez que afin de préserver l'intégrité de la ligne de requête ou de l'en-tête de requête, une ligne de requête complète ou un en-tête de requête doit être placé dans une mémoire continue. Par conséquent, une ligne de requête complète ou un en-tête de requête ne sera enregistré que. dans un tampon.
De cette façon, si la ligne de requête est plus grande que la taille d'un tampon, une erreur 414 sera renvoyée. Si la taille de l'en-tête de requête est supérieure à la taille d'un tampon, une erreur 400 sera renvoyée. Après avoir compris les valeurs de ces paramètres et les pratiques réelles de Nginx, dans le scénario d'application, nous devons ajuster ces paramètres en fonction des besoins réels pour optimiser notre programme.
Organigramme de traitement :
Ce qui précède est le cycle de vie d'une requête http dans Nginx.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!