Configurer un proxy dans NodeJS

Configurer un proxy dans NodeJS


Un projet récent nécessitait de faire passer un programme NodeJS par un proxy. Je pensais initialement que c’était juste une simple configuration, mais cela s’est avéré plus compliqué que prévu.

NodeJS ne lit pas par défaut le proxy système, et comme NodeJS a plusieurs méthodes pour envoyer des requêtes réseau, les méthodes de configuration du proxy sont également différentes. Voici un résumé.

Prérequis

Supposons d’abord que l’adresse du serveur proxy provient de variables d’environnement, c’est aussi la pratique standard de nombreuses applications web. Pour plus de commodité, appelons-les HTTP_PROXY et HTTPS_PROXY.

Fetch

NodeJS récent supporte l’interface Fetch, qui essaie de rester cohérente avec Fetch dans le navigateur, mais si c’était vraiment cohérent, il n’y aurait pas moyen de configurer le proxy. Heureusement, NodeJS a ouvert une porte en ajoutant un paramètre spécial dispatcher pour modifier les paramètres de requête réseau, y compris le serveur proxy.

Nous pouvons utiliser le package undici pour configurer le dispatcher :

npm install undici

Configurer le proxy pour fetch

Utiliser ProxyAgent pour configurer :

import { ProxyAgent } from "undici";

const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
  await fetch(url, { dispatcher: new ProxyAgent(proxyUrl) });
}

Configuration globale du proxy pour fetch

setGlobalDispatcher est utilisé pour configurer le proxy pour tous les fetch dans le programme NodeJS :

import { setGlobalDispatcher, ProxyAgent } from "undici";

const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
  setGlobalDispatcher(new ProxyAgent(proxyUrl));
}

Si vous voulez annuler le proxy, vous pouvez définir un Agent vide :

import { Agent, setGlobalDispatcher } from "undici";
setGlobalDispatcher(new Agent());

Principe

setGlobalDispatcher utilise en fait une entrée secrète de NodeJS. L’objet global de NodeJS a un Symbol pour définir le dispatcher global :

global[Symbol.for("undici.globalDispatcher.1")] = yourDispatcher;

Cela ne semble pas écrit dans la documentation de NodeJS (en tout cas je ne l’ai pas trouvé), pour voir les détails, allez sur : https://github.com/nodejs/node/issues/43187

En plus de configurer le proxy, que peut faire dispatcher

Si vous importez Agent au lieu de ProxyAgent, vous pouvez aussi configurer keepAlive, timeout et autres paramètres réseau :

import { Agent } from "undici";

const res = await fetch("https://example.com", {
  dispatcher: new Agent({
    keepAliveTimeout: 10,
    keepAliveMaxTimeout: 10,
  }),
});
const json = await res.json();
console.log(json);

Pour plus de détails, consultez la documentation d’undici.

Modules natifs NodeJS http et https

Comme mentionné ci-dessus, NodeJS n’a pas de méthode intégrée pour configurer le proxy, il faut utiliser http.Agent et https.Agent pour développer manuellement. Les packages populaires actuels sont respectivement http-proxy-agent et https-proxy-agent.

Voici un exemple avec https-proxy-agent :

import https from "https";
import { HttpsProxyAgent } from "https-proxy-agent";

const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
  const agent = new HttpsProxyAgent(proxyUrl);

  https.get(
    {
      host: "example.com",
      path: "/",
      agent,
    },
    (res) => {
      // Traiter la réponse
    }
  );
}

Axios

Axios est presque devenu le standard de l’industrie JavaScript. Il a plusieurs façons de configurer le proxy (priorité de bas en haut) :

  1. Variables d’environnement : Axios lit lui-même les variables d’environnement HTTP_PROXY et HTTPS_PROXY

  2. Paramètre proxy :

    import axios from "axios";
    
    axios.get("https://example.com", {
      proxy: {
        host: "127.0.0.1",
        port: 7890,
      },
    });
  3. Paramètres httpAgent et httpsAgent : Vous pouvez passer les http.Agent et https.Agent natifs de NodeJS pour contrôler les paramètres réseau.

    Nous utilisons ici http-proxy-agent et https-proxy-agent mentionnés dans le chapitre précédent :

    import axios from "axios";
    import { HttpsProxyAgent } from "https-proxy-agent";
    import { HttpProxyAgent } from "http-proxy-agent";
    
    const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
    if (proxyUrl) {
      const httpsAgent = new HttpsProxyAgent(proxyUrl);
      const httpAgent = new HttpProxyAgent(proxyUrl);
    
      const instance = axios.create({
        httpAgent,
        httpsAgent,
      });
    }

Pour plus de détails, consultez la documentation Axios.

Limitation des connexions HTTPS

J’ai découvert que si on utilise les deux premières méthodes pour configurer un proxy HTTP, axios ne peut pas établir de connexion HTTPS. La raison est qu’axios n’envoie pas la méthode CONNECT, donc ne peut pas établir de connexion TLS (si vous ne comprenez pas la méthode CONNECT, consultez cet article que j’ai écrit).