
NodeJSでプロキシを設定する
最近、あるプロジェクトで NodeJS にプロキシを使用する必要がありました。最初は単純な設定だと思っていましたが、意外と手間がかかりました。
NodeJS はデフォルトでシステムプロキシを読み取らず、また NodeJS にはネットワークリクエストを送信する方法が複数あるため、プロキシの設定方法も様々です。以下にまとめます。
前提条件
プロキシサーバーのアドレスは環境変数から取得すると仮定します。これは多くの Web アプリケーションの標準的な方法です。便宜上、これらをHTTP_PROXY
とHTTPS_PROXY
と呼びます。
Fetch
最近の NodeJS は Fetch インターフェースをサポートしており、ブラウザの Fetchとの一貫性を保とうとしていますが、完全に一貫性を保つとプロキシを設定する方法がなくなってしまいます。幸いなことに、NodeJS はdispatcher
という独自のパラメータを追加して、プロキシサーバーを含むネットワークリクエストパラメータを変更できるようにしました。
undici
パッケージを使用してdispatcher
を設定できます:
npm install undici
fetch プロキシの設定
ProxyAgent を使用して設定します:
import { ProxyAgent } from "undici";
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
await fetch(url, { dispatcher: new ProxyAgent(proxyUrl) });
}
グローバル fetch プロキシの設定
setGlobalDispatcher
は、NodeJS プログラム内のすべての fetch 呼び出しのプロキシを設定するために使用されます:
import { setGlobalDispatcher, ProxyAgent } from "undici";
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
setGlobalDispatcher(new ProxyAgent(proxyUrl));
}
プロキシを削除するには、空の Agent を設定できます:
import { Agent, setGlobalDispatcher } from "undici";
setGlobalDispatcher(new Agent());
仕組み
setGlobalDispatcher
は実際に NodeJS の隠れたエントリーポイントを使用しています。NodeJS のグローバルオブジェクトには、グローバルディスパッチャーを設定するための Symbol があります:
global[Symbol.for("undici.globalDispatcher.1")] = yourDispatcher;
これは NodeJS のドキュメントには記載されていないようです(少なくとも私は見つけられませんでした)。詳細については、https://github.com/nodejs/node/issues/43187 を参照してください。
プロキシ設定以外の dispatcher の機能
ProxyAgent
の代わりにAgent
をインポートすると、keepAlive や timeout などのネットワークパラメータも設定できます:
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);
詳細については、undici のドキュメントを参照してください。
NodeJS ネイティブモジュール http と https
上記のように、NodeJS にはプロキシを設定するための組み込みメソッドがないため、http.Agent
とhttps.Agent
を使用して開発する必要があります。現在、人気のあるパッケージはhttp-proxy-agent
とhttps-proxy-agent
です。
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) => {
// レスポンスの処理
}
);
}
Axios
Axios は JavaScript の業界標準と言っても過言ではありません。プロキシを設定する方法は複数あります(優先度の低い順):
-
環境変数:Axios 自体が環境変数
HTTP_PROXY
とHTTPS_PROXY
を読み取ります -
proxy
パラメータ:import axios from "axios"; axios.get("https://example.com", { proxy: { host: "127.0.0.1", port: 7890, }, });
-
httpAgent
とhttpsAgent
パラメータ:NodeJS の組み込みhttp.Agent
とhttps.Agent
を渡して、ネットワークパラメータを制御できます。前のセクションで言及した
http-proxy-agent
とhttps-proxy-agent
を使用します: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, }); }
詳細については、Axios ドキュメントを参照してください。
HTTPS 接続の制限
最初の 2 つの方法で HTTP プロキシを設定すると、Axios は HTTPS 接続を確立できないことがわかりました。その理由は、Axios が CONNECT メソッドを送信しないため、TLS 接続を確立できないことです(CONNECT メソッドについて理解していない場合は、この記事を読んでください)。