Node.js est une plate-forme serveur. La tĂąche principale du serveur est de traiter les demandes des clients, en particulier des navigateurs, aussi rapidement et efficacement que possible. Le huitiĂšme de la traduction du didacticiel Node.js que nous publions aujourd'hui concerne HTTP et WebSocket.

[Nous vous conseillons de lire] Autres parties du cyclePartie 1:
Informations générales et mise en routePartie 2:
JavaScript, V8, quelques astuces de développementPartie 3:
Hébergement, REPL, travailler avec la console, les modulesPartie 4:
fichiers npm, package.json et package-lock.jsonPartie 5:
npm et npxPartie 6:
boucle d'événements, pile d'appels, temporisateursPartie 7:
Programmation asynchronePartie 8:
Guide Node.js, Partie 8: Protocoles HTTP et WebSocketPartie 9:
Guide Node.js, partie 9: utilisation du systĂšme de fichiersPartie 10:
Guide Node.js, Partie 10: Modules standard, flux, bases de donnĂ©es, NODE_ENVPDF complet du guide Node.js Que se passe-t-il lors des requĂȘtes HTTP?
Parlons de la façon dont les navigateurs font des requĂȘtes aux serveurs en utilisant le protocole HTTP / 1.1.
Si vous avez dĂ©jĂ eu une interview dans le domaine informatique, il se peut que l'on vous demande ce qui se passe lorsque vous tapez quelque chose dans la barre d'adresse de votre navigateur et appuyez sur EntrĂ©e. C'est peut-ĂȘtre l'une des questions les plus populaires qui se posent lors de ces entretiens. Quiconque pose de telles questions veut savoir si vous pouvez expliquer des concepts assez simples et savoir si vous comprenez les principes d'Internet.
Cette question touche à de nombreuses technologies, pour comprendre les principes généraux de ce qui signifie comprendre comment est construit l'un des systÚmes les plus complexes jamais construits par l'humanité, qui couvre le monde entier.
â Protocole HTTP
Les navigateurs modernes sont capables de distinguer les URL rĂ©elles entrĂ©es dans leur barre d'adresse des requĂȘtes de recherche, pour le traitement desquelles le moteur de recherche par dĂ©faut est gĂ©nĂ©ralement utilisĂ©. Nous parlerons des URL. Si vous entrez une adresse de site Web, telle que
flaviocopes.com
, dans la ligne du navigateur, le navigateur convertit cette adresse au
flaviocopes.com
http://flaviocopes.com
, en supposant que le protocole HTTP sera utilisé pour échanger des données avec la ressource spécifiée. Veuillez noter que sous Windows, ce dont nous allons parler ici peut sembler un peu différent de celui sous macOS et Linux.
â Phase de recherche DNS
Ainsi, le navigateur, en commençant à télécharger des données à partir de l'adresse demandée par les utilisateurs, effectue l'opération de recherche DNS (DNS Lookup) afin de trouver l'adresse IP du serveur correspondant. Les noms symboliques des ressources saisies dans la barre d'adresse conviennent aux utilisateurs, mais le périphérique Internet implique la possibilité d'échanger des données entre des ordinateurs à l'aide d'adresses IP, qui sont des ensembles de nombres comme 222.324.3.1 (pour IPv4).
Tout d'abord, en découvrant l'adresse IP du serveur, le navigateur examine le cache DNS local pour voir si une procédure similaire a été effectuée récemment. Dans le navigateur Chrome, par exemple, il existe un moyen pratique de consulter le cache DNS en entrant l'adresse suivante dans la barre d'adresse:
chrome://net-internals/#dns
.
Si rien ne se trouve dans le cache, le navigateur utilise l'appel systĂšme POSIX
gethostbyname
pour connaĂźtre l'adresse IP du serveur.
â fonction gethostbyname
La fonction
gethostbyname
vérifie d'abord le
hosts
, qui, sur macOS ou Linux, peut ĂȘtre trouvĂ© dans
/etc/hosts
afin de savoir si des informations locales peuvent ĂȘtre trouvĂ©es en recherchant l'adresse du serveur.
Si des moyens locaux pour résoudre la demande de découverte de l'adresse IP du serveur échouent, le systÚme effectue une demande au serveur DNS. Les adresses de ces serveurs sont stockées dans les paramÚtres systÚme.
Voici quelques serveurs DNS populaires:
- 8.8.8.8: serveur DNS Google.
- 1.1.1.1: Serveur DNS CloudFlare.
La plupart des gens utilisent les serveurs DNS fournis par leurs fournisseurs. Le navigateur effectue des requĂȘtes DNS Ă l'aide du protocole UDP.
TCP et UDP sont deux protocoles de base utilisĂ©s dans les rĂ©seaux informatiques. Ils sont situĂ©s au mĂȘme niveau conceptuel, mais TCP est un protocole orientĂ© connexion, et pour l'Ă©change de messages UDP, dont le traitement crĂ©e une petite charge supplĂ©mentaire sur le systĂšme, une procĂ©dure d'Ă©tablissement de connexion n'est pas nĂ©cessaire. Nous ne parlerons pas exactement de la façon dont les donnĂ©es sont Ă©changĂ©es via UDP.
L'adresse IP correspondant au nom de domaine qui nous intĂ©resse peut ĂȘtre dans le cache du serveur DNS. Si ce n'est pas le cas, il contactera le serveur DNS racine. Le systĂšme de serveur DNS racine se compose de 13 serveurs, dont dĂ©pend le fonctionnement de l'ensemble de l'Internet.
Il convient de noter que le serveur DNS racine ne connaßt pas la correspondance entre tous les noms de domaine et adresses IP existants dans le monde. Mais des serveurs similaires connaissent les adresses des serveurs DNS de niveau supérieur pour des domaines tels que .com, .it, .pizza, etc.
DÚs réception de la demande, le serveur DNS racine la redirige vers le serveur DNS du domaine de premier niveau, vers le serveur dit TLD (à partir du domaine de premier niveau).
Supposons que le navigateur recherche l'adresse IP du serveur
flaviocopes.com
. En ce qui concerne le serveur DNS racine, le navigateur recevra de celui-ci l'adresse du serveur TLD pour la zone .com. Maintenant, cette adresse sera stockée dans le cache, par conséquent, si vous avez besoin de trouver l'adresse IP d'une autre URL à partir de la zone .com, vous n'aurez plus à accéder au serveur DNS racine.
Les serveurs TLD ont des adresses IP de serveurs de noms (Name Server, NS), Ă l'aide desquels vous pouvez trouver l'adresse IP Ă partir de l'URL que nous avons. OĂč le serveur NS obtient-il ces informations? Le fait est que si vous achetez un domaine, le registraire de domaine envoie des donnĂ©es Ă ce sujet aux serveurs de noms. Une procĂ©dure similaire est effectuĂ©e, par exemple, lors du changement d'hĂ©bergement.
Les serveurs en question appartiennent généralement à des hébergeurs. En rÚgle générale, pour se protéger contre les pannes, plusieurs de ces serveurs sont créés. Par exemple, ils peuvent avoir ces adresses:
- ns1.dreamhost.com
- ns2.dreamhost.com
- ns3.dreamhost.com
Pour connaßtre l'adresse IP par URL, ils se tournent finalement vers ces serveurs. Ils stockent les données réelles sur les adresses IP.
Maintenant, aprÚs avoir réussi à trouver l'adresse IP derriÚre l'URL entrée dans la barre d'adresse du navigateur, nous passons à l'étape suivante de notre travail.
â Etablissement d'une connexion TCP
AprÚs avoir appris l'adresse IP du serveur, le client peut établir une connexion TCP avec lui. Lors de l'établissement d'une connexion TCP, le client et le serveur se transmettent mutuellement des données de service, aprÚs quoi ils peuvent échanger des informations. Cela signifie qu'une fois la connexion établie, le client pourra envoyer une demande au serveur.
âEnvoyer une demande
Une demande est un fragment de texte structuré conformément aux rÚgles du protocole utilisé. Il se compose de trois parties:
- ChaĂźne de requĂȘte
- En-tĂȘte de demande.
- Demander le corps.
ChaĂźne de requĂȘte
La chaĂźne de requĂȘte est une chaĂźne de texte unique qui contient les informations suivantes:
- Méthode HTTP.
- Adresse de la ressource
- Version du protocole.
Cela peut ressembler, par exemple, Ă ceci:
GET / HTTP/1.1
En-tĂȘte de demande
L'en-tĂȘte de demande est reprĂ©sentĂ© par un ensemble de
:
. Il y a 2 champs d'en-tĂȘte obligatoires, dont l'un est
Host
et le second est
Connection
. Les champs restants sont facultatifs.
Le titre peut ressembler Ă ceci:
Host: flaviocopes.com Connection: close
Le champ
Host
indique le nom de domaine qui intéresse le navigateur. Le champ
Connection
, défini sur
close
, signifie que la connexion entre le client et le serveur n'a pas besoin d'ĂȘtre maintenue ouverte.
Les autres en-tĂȘtes de demande couramment utilisĂ©s sont les suivants:
Origin
Accept
Accept-Encoding
Cookie
Cache-Control
Dnt
En fait, il y en a beaucoup plus.
L'en-tĂȘte de demande se termine par une chaĂźne vide.
Organe de demande
Le corps de la demande est facultatif; il n'est pas utilisĂ© dans les demandes GET. Le corps de la requĂȘte est utilisĂ© dans les requĂȘtes POST, ainsi que dans d'autres requĂȘtes. Il peut contenir, par exemple, des donnĂ©es au format JSON.
Puisque nous parlons maintenant d'une requĂȘte GET, le corps de la requĂȘte sera vide, nous ne travaillerons pas avec.
â RĂ©pondre
Une fois que le serveur a reçu la demande envoyée par le client, il la traite et envoie une réponse au client.
La réponse commence par un code d'état et un message correspondant. Si la demande aboutit, le début de la réponse ressemblera à ceci:
200 OK
En cas de problÚme, il peut y avoir d'autres codes. Par exemple, les éléments suivants:
404 Not Found
403 Forbidden
301 Moved Permanently
500 Internal Server Error
304 Not Modified
401 Unauthorized
De plus, la rĂ©ponse contient une liste d'en-tĂȘtes HTTP et le corps de la rĂ©ponse (qui, puisque la demande est exĂ©cutĂ©e par le navigateur, sera du code HTML).
Analyse HTML
Une fois que le navigateur a reçu la réponse du serveur, dont le corps contient du code HTML, il commence à l'analyser, en répétant le processus ci-dessus pour chaque ressource nécessaire pour former la page. Ces ressources comprennent, par exemple, les éléments suivants:
- Fichiers CSS.
- Les images
- IcĂŽne de page Web (favicon).
- Fichiers JavaScript.
La façon exacte dont le navigateur affiche la page ne s'applique pas à notre conversation. La principale chose qui nous intéresse ici est que le processus de demande et de réception de données ci-dessus est utilisé non seulement pour le code HTML, mais aussi pour tout autre objet transféré du serveur au navigateur à l'aide du protocole HTTP.
à propos de la création d'un serveur simple à l'aide de Node.js
Maintenant, aprÚs avoir examiné le processus d'interaction entre le navigateur et le serveur, vous pouvez jeter un nouveau regard sur la section d'application First Node.js de la
premiÚre partie de cette série de documents, dans laquelle nous avons décrit le code d'un serveur simple.
Faire des requĂȘtes HTTP avec Node.js
Pour effectuer des requĂȘtes HTTP Ă l'aide de Node.js, le
module approprié
est utilisé . Les exemples ci-dessous utilisent le module
https . Le fait est que dans les conditions modernes, dans la mesure du possible, il est nécessaire d'utiliser le protocole HTTPS.
â ExĂ©cution des requĂȘtes GET
Voici un exemple d'exécution d'une demande GET à l'aide de Node.js:
const https = require('https') const options = { hostname: 'flaviocopes.com', port: 443, path: '/todos', method: 'GET' } const req = https.request(options, (res) => { console.log(`statusCode: ${res.statusCode}`) res.on('data', (d) => { process.stdout.write(d) }) }) req.on('error', (error) => { console.error(error) }) req.end()
ExecutionExĂ©cution de la requĂȘte POST
Voici comment effectuer une demande POST Ă ââpartir de Node.js:
const https = require('https') const data = JSON.stringify({ todo: 'Buy the milk' }) const options = { hostname: 'flaviocopes.com', port: 443, path: '/todos', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': data.length } } const req = https.request(options, (res) => { console.log(`statusCode: ${res.statusCode}`) res.on('data', (d) => { process.stdout.write(d) }) }) req.on('error', (error) => { console.error(error) }) req.write(data) req.end()
UTPUT et DELETE requĂȘtes
L'exĂ©cution de ces requĂȘtes ressemble Ă celle des requĂȘtes POST. La principale diffĂ©rence, outre le contenu sĂ©mantique de ces opĂ©rations, est la valeur de la propriĂ©tĂ©
method
de l'objet
options
.
â ExĂ©cution de requĂȘtes HTTP dans Node.js Ă l'aide de la bibliothĂšque Axios
Axios est une bibliothĂšque JavaScript trĂšs populaire qui fonctionne Ă la fois dans le navigateur (cela inclut tous les navigateurs modernes et IE, Ă commencer par IE8), et dans l'environnement Node.js, qui peut ĂȘtre utilisĂ© pour effectuer des requĂȘtes HTTP.
Cette bibliothÚque est basée sur des promesses, elle présente certains avantages par rapport aux mécanismes standard, en particulier par rapport à l'API Fetch. Ses avantages sont les suivants:
- Prise en charge des anciens navigateurs (vous avez besoin d'un polyfill pour utiliser Fetch).
- Possibilité d'interrompre les demandes.
- Prise en charge de la définition des délais d'expiration des demandes.
- Protection intégrée contre les attaques CSRF.
- Prise en charge du téléchargement de données avec la fourniture d'informations sur l'avancement de ce processus.
- Prise en charge de la conversion de données JSON.
- Emplois chez Node.js
L'installation
Vous pouvez utiliser npm pour installer Axios:
npm install axios
Le mĂȘme effet peut ĂȘtre obtenu avec du fil:
yarn add axios
Vous pouvez connecter la bibliothĂšque Ă la page en utilisant
unpkg.com
:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
API Axios
Vous pouvez faire une requĂȘte HTTP en utilisant l'objet
axios
:
axios({ url: 'https://dog.ceo/api/breeds/list/all', method: 'get', data: { foo: 'bar' } })
Mais il est généralement plus pratique d'utiliser des méthodes spéciales:
Ceci est similaire à la façon dont jQuery utilise
$.get()
et
$.post()
au lieu de
$.ajax()
$.post()
.
Axios propose des mĂ©thodes distinctes pour exĂ©cuter d'autres types de requĂȘtes HTTP, qui ne sont pas aussi populaires que GET et POST, mais sont toujours utilisĂ©es:
axios.delete()
axios.put()
axios.patch()
axios.options()
La bibliothĂšque dispose d'une mĂ©thode pour exĂ©cuter une demande conçue pour recevoir uniquement des en-tĂȘtes HTTP, sans le corps de la rĂ©ponse:
GET demandes
Axios est pratique à utiliser en utilisant la syntaxe asynchrone / attente moderne. L'exemple de code suivant, conçu pour Node.js, utilise la bibliothÚque pour charger une liste de races de chiens à partir de
l'API Dog . Ici, la méthode
axios.get()
est appliquée et les roches sont comptées:
const axios = require('axios') const getBreeds = async () => { try { return await axios.get('https://dog.ceo/api/breeds/list/all') } catch (error) { console.error(error) } } const countBreeds = async () => { const breeds = await getBreeds() if (breeds.data.message) { console.log(`Got ${Object.entries(breeds.data.message).length} breeds`) } } countBreeds()
Le mĂȘme peut ĂȘtre réécrit sans utiliser async / wait, en appliquant des promesses:
const axios = require('axios') const getBreeds = () => { try { return axios.get('https://dog.ceo/api/breeds/list/all') } catch (error) { console.error(error) } } const countBreeds = async () => { const breeds = getBreeds() .then(response => { if (response.data.message) { console.log( `Got ${Object.entries(response.data.message).length} breeds` ) } }) .catch(error => { console.log(error) }) } countBreeds()
Utilisation de paramĂštres dans les requĂȘtes GET
Une requĂȘte GET peut contenir des paramĂštres qui ressemblent Ă ceci dans une URL:
https:
Lorsque vous utilisez Axios, une requĂȘte de ce type peut ĂȘtre effectuĂ©e comme suit:
axios.get('https:
Le mĂȘme effet peut ĂȘtre obtenu en dĂ©finissant la propriĂ©tĂ©
params
dans un objet avec des paramĂštres:
axios.get('https://site.com/', { params: { foo: 'bar' } })
Demandes POST
L'exĂ©cution des requĂȘtes POST est trĂšs similaire Ă l'exĂ©cution des requĂȘtes GET, mais ici, au lieu de la mĂ©thode
axios.get()
, la méthode
axios.post()
est utilisée:
axios.post('https:
Comme deuxiÚme argument, la méthode
post
accepte un objet avec des paramĂštres de requĂȘte:
axios.post('https://site.com/', { foo: 'bar' })
Utilisation du protocole WebSocket dans Node.js
WebSocket est une alternative Ă HTTP, il peut ĂȘtre utilisĂ© pour organiser l'Ă©change de donnĂ©es dans des applications Web. Ce protocole vous permet de crĂ©er des canaux de communication bidirectionnels de longue durĂ©e entre le client et le serveur. Une fois la connexion Ă©tablie, le canal de communication reste ouvert, ce qui met l'application Ă la disposition d'une connexion trĂšs rapide, caractĂ©risĂ©e par de faibles latences et une faible charge supplĂ©mentaire sur le systĂšme.
Le protocole WebSocket est pris en charge par tous les navigateurs modernes.
â DiffĂ©rences HTTP
HTTP et WebSocket sont des protocoles trÚs différents qui utilisent différentes approches pour l'échange de données. HTTP est basé sur le modÚle «request-response»: le serveur envoie des données au client aprÚs leur demande. Dans le cas de WebSocket, tout est organisé différemment. à savoir:
- Le serveur peut envoyer des messages au client de sa propre initiative, sans attendre une demande du client.
- Le client et le serveur peuvent Ă©changer des donnĂ©es en mĂȘme temps.
- Lors de la transmission d'un message, une quantitĂ© extrĂȘmement faible de donnĂ©es de service est utilisĂ©e. Cela conduit notamment Ă une faible latence dans la transmission des donnĂ©es.
Le protocole WebSocket est trĂšs bien adaptĂ© aux communications en temps rĂ©el sur des canaux qui restent ouverts pendant longtemps. HTTP, Ă son tour, est excellent pour organiser des sessions de communication occasionnelles initiĂ©es par le client. Dans le mĂȘme temps, il convient de noter que, d'un point de vue de la programmation, il est beaucoup plus facile de mettre en Ćuvre l'Ă©change de donnĂ©es en utilisant le protocole HTTP qu'en utilisant le protocole WebSocket.
â Version protĂ©gĂ©e du protocole WebSocket
Il existe une version non sécurisée du protocole WebSocket (schéma
ws://
URI), qui ressemble, en termes de sécurité, au protocole
http://
. L'utilisation de
ws://
doit ĂȘtre Ă©vitĂ©e, prĂ©fĂ©rant une version sĂ©curisĂ©e du protocole -
wss://
.
âCrĂ©ation d'une connexion WebSocket
Pour créer une connexion WebSocket, vous devez utiliser le
constructeur approprié:
const url = 'wss://myserver.com/something' const connection = new WebSocket(url)
Une fois la connexion établie, l'événement
open
est déclenché. Vous pouvez organiser cet événement en affectant une fonction de rappel à la propriété
onopen
de l'objet de
connection
:
connection.onopen = () => {
Pour gérer les erreurs, le
onerror
événements
onerror
est utilisé:
connection.onerror = error => { console.log(`WebSocket error: ${error}`) }
âEnvoyer des donnĂ©es au serveur
AprĂšs avoir ouvert une connexion WebSocket au serveur, vous pouvez lui envoyer des donnĂ©es. Cela peut ĂȘtre fait, par exemple, dans le
onopen
onopen:
connection.onopen = () => { connection.send('hey') }
â Obtention des donnĂ©es du serveur
Pour recevoir des données envoyées à l'aide du protocole WebSocket du serveur, vous pouvez affecter le
onmessage
onmessage, qui sera appelé lorsque l'événement de
message
est reçu:
connection.onmessage = e => { console.log(e.data) }
â ImplĂ©mentation du serveur WebSocket dans l'environnement Node.js
Afin d'implémenter un serveur WebSocket dans l'environnement Node.js, vous pouvez utiliser la bibliothÚque
ws populaire. Nous l'utilisons pour le développement de serveurs, mais il convient à la création de clients, ainsi qu'à l'organisation de l'interaction entre deux serveurs.
Installez cette bibliothĂšque en initialisant d'abord le projet:
yarn init yarn add ws
Le code du serveur WebSocket que nous devons écrire est assez compact:
constWebSocket = require('ws') const wss = newWebSocket.Server({ port: 8080 }) wss.on('connection', ws => { ws.on('message', message => { console.log(`Received message => ${message}`) }) ws.send('ho!') })
Ici, nous créons un nouveau serveur qui écoute sur le port standard 8080 pour le protocole WebSocket et décrivons un rappel qui, lorsque la connexion est établie, envoie un message
ho!
au client
ho!
et imprime sur la console un message reçu du client.
Voici un exemple de travail d'un serveur WebSocket, et
voici un client qui peut interagir avec lui.
Résumé
Aujourd'hui, nous avons parlé des mécanismes de mise en réseau pris en charge par la plateforme Node.js, établissant des parallÚles avec des mécanismes similaires utilisés dans les navigateurs. Notre prochain sujet portera sur les fichiers.
Chers lecteurs! Utilisez-vous le protocole WebSocket dans vos applications Web, dont le cÎté serveur a été créé à l'aide de Node.js?