Maison > Article > interface Web > Introduction détaillée à l'implémentation http dans NODEJS
Cet article présente principalement le processus technique et l'analyse détaillée de l'implémentation http de NODEJS. Les amis qui en ont besoin peuvent s'y référer.
1. Avant-propos
À l'heure actuelle, le protocole HTTP est le protocole réseau le plus utilisé sur Internet, et c'est aussi celui qui ER front-end a le plus de contacts avec le type d'accord. En lisant l'implémentation du module http dans nodejs, vous pouvez avoir une compréhension plus approfondie du protocole HTTP. Le protocole HTTP est un protocole de couche application basé sur le protocole TCP, et sa mise en œuvre est indissociable de la famille de protocoles TCP/IP. Quant à l'implémentation du code, le module http dépend du module net.
Comme le montre la figure ci-dessous : dans nodejs, http transmet les données via le module net, et après avoir obtenu les données, il s'appuie sur HTTP_PARSER pour analyser les données.
2. Code source
Démarrer un service HTTP
Démarrer un service HTTP dans nodejs est très simple, il suffit d'instancier un objet Server et écoute un certain port :
const Server = require('./libs/http').Server const server = new Server( function(req, res) { res.writeHead(200) res.end('hello world') }) server.listen(9999)
Classe SERVER
La classe Server hérite de net.Server et écoute l'événement 'connection'.
Dans la classe Server, deux choses principales sont effectuées : 1. Initialiser le module NET et établir la surveillance du réseau TCP 2. Surveiller son propre événement de requête
Lorsque la requête du client arrive, le serveur L'instance écoutera d'abord l'événement 'connection', établira une connexion TCP et exposera l'objet socket dans connectionListener. Ensuite, le module HTTP interagit avec le client via l'objet socket.
Lorsqu'une requête arrive, le serveur déclenchera son propre événement de requête et appellera la méthode requestListener, qui est la fonction de rappel transmise lors de la création de l'instance du serveur.
new Server( function(req, res) { res.writeHead(200) res.end('hello world') })
Remarque : L'objet socket est similaire à une implémentation du protocole TCP, via lequel les données peuvent être échangées avec le client. Remarque : Dans la fonction connectionListener, l'instance d'analyseur est également initialisée et liée à. it. onIncoming function HTTP Parser
L'ensemble du processus d'analyse est effectué dans connectionListener, et le socket obtient les données poussées par TCP via l'événement 'data'
Lorsque le socket obtient les données, il le fera d'abord. analyser les données, c'est-à-dire : parser .excute(), l'outil d'analyse est parser. Il convient de mentionner que afin de réutiliser l'analyseur, l'auteur l'a obtenu à partir d'un « pool FreeList ».
... const parser = parsers.alloc() ... connectionListener(socket) { socket.on('data', socketOnData) // TCP推入数据,parser进行解析 function socketOnData(d) { ... const ret = parser.execute(d) ... } }
1. Lorsque les données TCP arrivent, exécutez() d'abord
2. En suivant les indices, nous constatons que parser.excute est Excute (node_http_parser.cc). Excute n'est qu'une sous-traitance, et le travail spécifique est effectué par http_parser_excute (http_parser.c).
node_http_parser.cc n'est qu'un wrapper pour http_parser.c. http_parser.c s'appuie sur les 7 fonctions périodiques de rappel exposées en externe pour interagir avec node_http_parser.cc pour les données.
3. http_parser.c n'a que deux types de rappels : HTTP_CB et HTTP_DATA_CB. Grâce à la surcharge, 8 fonctions périodiques sont enregistrées dans ces deux types de fonctions, comme indiqué ci-dessous :
4. Bien que http_parser enregistre 8 fonctions de rappel, node_http_parser.cc n'expose que quatre cycles au monde extérieur. Fonction :
parserOnHeadersparserOnHeadersCompleteparserOnBodyparserOnMessageComplete5. Lorsque http_parser.c analyse on_headers_complete, exécutez la fonction de rappel HTTP_CB( on_headers_complete), comme le montre la figure : La fonction de rappel kOnHeadersComplete sera exécutée dans la fonction, c'est-à-dire : fonction parserOnHeadersComplete (common.js) À ce stade, l'analyse de l'en-tête de la requête est effectuée. essentiellement terminé, puis créez une instance d'IncomingMessage, puis enveloppez les données d'en-tête de demande dans l'instance.Exécutez la fonction de rappel onIncoming et transmettez l'instance IncomingMessage obtenue en tant que paramètre.
function parserOnHeadersComplete (versionMajor, versionMinor, headers, method, url, statusCode, statusMessage, upgrade, shouldKeepAlive) { ... parser.incoming = new IncomingMessage(parser.socket) parser.incoming.httpVersionMajor = versionMajor parser.incoming.httpVersionMinor = versionMinor parser.incoming.httpVersion = versionMajor + '.' + versionMinor parser.incoming.url = url ... skipBody = parser.onIncoming(parser.incoming, shouldKeepAlive) }7. Dans parserOnIncoming, créez une instance ServerResponse. Possède deux instances de req et res, puis déclenche l'événement de requête surveillé par le serveur. Lorsque le serveur est instancié, requestListener est utilisé comme paramètre de fonction pour écouter l'événement de requête. 8. Retour à la création du serveur :
const server = new Server( function(req, res) { var data = '' req.on('data', function(chunk){ console.log('chunk: ' + chunk) data += chunk; }) res.writeHead(200) res.end('hello world') })En résumé, après que http_parser ait analysé l'en-tête, l'événement de requête sera déclenché. Où doivent être placées les données du corps ? En fait, les données du corps seront placées dans le flux jusqu'à ce que l'utilisateur utilise l'événement de données pour recevoir les données. En d’autres termes, lorsque la requête est déclenchée, le corps ne sera pas analysé.
3. Tri des processus
La requête http complète est comme ceci : - Le client initie une requête HTTP et déclenche d'abord l'événement de connexion sur côté serveur. Établissez un lien TCP. Après avoir reçu l'événement de connexion, le serveur établit une connexion TCP, expose le socket et écoute l'événement 'data' via le socket ; il initialise l'analyseur http pour préparer l'analyse ultérieure des données. Les données de la requête HTTP atteignent le serveur et l'analyseur exécute la méthode d'exécution pour analyser. Une fois l'en-tête de la requête analysé avec succès, l'événement de requête est déclenché via un rappel. À ce stade, nous avons reçu la demande de cette requête http dans la fonction de rappel du serveur4. Conclusion
Étant donné que de nombreuses bibliothèques sous-jacentes de nodejs sont écrites en C++/C, cela est très gênant pendant le processus de lecture et de débogage. Lorsque j'ai lu moi-même le code source, je me suis concentré uniquement sur la partie JS du code source. Par exemple, la poignée de main à trois voies et la vague à quatre voies de TCP ne sont pas approfondies dans les détails de leur implémentation. L'analyse ci-dessus n'implique pas l'analyse de http-body. Pour les requêtes réseau avec body, la situation réelle est plus compliquée et certains détails ne sont pas entièrement compris. Lorsque je résumerai et partagerai la prochaine fois, je ferai de mon mieux pour compléter tous les détails manquants.
J'ai compilé ce qui précède pour vous, j'espère que cela vous sera utile à l'avenir.
Articles connexes :
Comment obtenir des éléments de nœud à l'aide de JS
Comment implémenter la fonction WebSocket à l'aide de NodeJS
À propos de l'utilisation réelle de log4js dans Express
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!