# Node.js プロキシ設定: Axios, Fetch, Undici & ローテーション

axios のプロキシオプションは HTTPS ターゲットで罠になり、ネイティブの fetch はプロキシ環境変数を完全に無視します。ここでは、axios、fetch、undici で機能する設定を紹介します — エージェント、認証、SOCKS5、ローテーション、ストリーミング。

Node.js のリクエストをプロキシ経由でルーティングするのは一行で済むように見えて、デバッグに午後を費やすことになります。その理由は、ほとんどのプロジェクトで使用される 3 つの HTTP クライアント — axios、Node 18 でグローバルとして出荷されたネイティブの `fetch`、および基盤となる undici ライブラリ — がそれぞれ異なる方法でプロキシを受け取り、期待通りに動作しないからです。axios には組み込みの `proxy` 設定があり、Node 専用で、HTTP プロキシの背後にある HTTPS ターゲットに対して静かに壊れています。このバグは 2020 年から axios の GitHub トラッカーにオープンされており、Stack Overflow で多くの票を集めたスレッドを引き起こしました。一方、ネイティブの fetch は `HTTP_PROXY` 環境変数を無視し、プロキシオプションをまったく持っていません。このガイドでは、各クライアントで実際に機能する設定、認証、SOCKS5、ローテーション、ストリーミングを紹介します。

## Axios プロキシ設定 vs プロキシエージェント

Axios は `proxy` オブジェクト — `{ host, port, auth }` — を備えており、プレーン HTTP ターゲットには問題なく機能します。罠は HTTPS にあります: ターゲットが `https://` でプロキシが HTTP を話す場合、axios は CONNECT トンネルを開くことができず、リクエストがハングするか、実際の IP で戻ってきます。コミュニティが合意した修正は、組み込みの設定を完全にバイパスし、代わりに axios にプロキシエージェントを渡し、`proxy: false` を設定して、2 つのメカニズムが競合しないようにすることです:

```js
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";

// Note the destructured import — a default import is the classic gotcha.
const agent = new HttpsProxyAgent("http://USER:PASS@residentialpremium.quantumproxies.io:8080");

const client = axios.create({
  httpAgent: agent,   // for http:// targets
  httpsAgent: agent,  // for https:// targets
  proxy: false,       // disable axios' own broken proxy handling
  timeout: 15000,
});

const r = await client.get("https://httpbin.org/ip");
console.log(r.data); // { origin: "<proxy exit IP>" }
```

2 つの詳細が時間を節約します。まず、**分解された** `{ HttpsProxyAgent }` インポートを使用します — 最近のバージョンでは名前付きシンボルとしてエクスポートされ、デフォルトのインポートは構築時に例外を投げるオブジェクトを与えます。次に、プロキシ URL スキームはプロキシが HTTPS トラフィックを運ぶ場合でも `http://` のままです: スキームはプロキシへの到達方法を説明し、ターゲットへの TLS はトンネル内で実行されます。同じ失敗クラスは Python でも見られます; requests でも作業している場合、パターンは私たちの [ProxyError および SSLError 修正ガイド](https://quantumproxies.io/blog/python-requests-proxyerror-fix) と共鳴します。

## 認証と環境変数

認証されたプロキシは HTTP ベーシック認証を使用します。エージェントを使用する場合、URL に `http://user:pass@host:port` として埋め込みます; パスワードに `@`、`:`、`/` が含まれている場合は、`encodeURIComponent()` で URL エンコードして、URL が間違った場所で分割されないようにします。`407 Proxy Authentication Required` は、資格情報が拒否されたか、ソース IP がホワイトリストに登録されていないことを意味します。axios はまた、`HTTP_PROXY`、`HTTPS_PROXY`、`NO_PROXY` を環境から読み取ります — サードパーティライブラリをコードに触れずにプロキシするのに便利です — そして、`proxy: false` を設定することでそれを無効にします。重要な警告: ネイティブの `fetch` はこれらの変数を**読み取りません**、したがって、env-var プロキシングに依存するスクレーパーは、axios から fetch に切り替えた瞬間に直接接続されます。

![同じリクエストに対する3つのコードスニペット：axiosはproxy: falseとともにhttpAgentとhttpsAgentにHttpsProxyAgentを渡し、ネイティブのfetchは呼び出しごとにundiciのdispatcherを受け取り、undiciのsetGlobalDispatcherにProxyAgentを渡すとプロセス全体がプロキシ経由になる。これらの混同が「proxy not working」の最大の原因だ。](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335145/blog/generated/qp-b9-007-diag1.png)
*同じリクエスト、3 つの配管システム。axios はエージェントを必要とし、ネイティブ fetch は undici ディスパッチャーを必要とし、それらを混ぜることが「プロキシが機能しない」の主な原因です。*

## ネイティブ fetch を undici でプロキシする

Node のグローバル `fetch` は undici 上に構築されており、プロキシは undici にあります。`ProxyAgent` を作成し、非標準の `dispatcher` オプションとして渡します — これは fetch をプロキシするための現代的で依存性の少ない方法であり、HTTPS CONNECT を箱から出して正しく処理します:

```js
import { ProxyAgent } from "undici";

const dispatcher = new ProxyAgent({
  uri: "http://residentialpremium.quantumproxies.io:8080",
  token: "Basic " + Buffer.from("USER:PASS").toString("base64"),
});

const res = await fetch("https://httpbin.org/ip", { dispatcher });
console.log(await res.json());
```

グローバル fetch ではなく undici を直接使用している場合、同じ `ProxyAgent` を `request()` または `setGlobalDispatcher()` にプラグインして、プロセス内のすべての fetch を一度にプロキシします。この単一呼び出しのグローバルスイッチは、ディスパッチャーをすべての関数に通すことなく、コードベース全体をプロキシ経由でルーティングする最もクリーンな方法です。

## Node.js における SOCKS5 プロキシ

axios も undici も SOCKS をネイティブにサポートしていません — axios の `proxy` 設定に `socks5://` 文字列を渡すと、`protocol mismatch` アサーションが発生します。`socks-proxy-agent` をインストールし、HTTPS エージェントと同じ方法で使用し、`httpAgent` と `httpsAgent` の両方に接続します。`socks5://` よりも `socks5h://` を好む: 末尾の `h` はプロキシ側で DNS を解決し、DNS リークを防ぎ、出口地点からの地理的に制限されたホスト名を解決します。すべての [SOCKS5 プロキシ](https://quantumproxies.io/socks5-proxies) プランは、HTTP と SOCKS5 の同じゲートウェイを公開しているので、これはスキームの切り替えであり、新しい購入ではありません:

```js
import axios from "axios";
import { SocksProxyAgent } from "socks-proxy-agent";

const agent = new SocksProxyAgent("socks5h://USER:PASS@residentialpremium.quantumproxies.io:1080");

const client = axios.create({ httpAgent: agent, httpsAgent: agent });
const r = await client.get("https://httpbin.org/ip");
console.log(r.data);
```

## プロキシリストなしのローテーション

古いレシピ — IP の配列、リクエストごとの `Math.random()`、死んだものを剪定 — はもはや維持しないコードです。ローテーションゲートウェイは、リクエストごとにサーバー側で新しい出口 IP を割り当てるので、1 つのエンドポイントがプール全体のように振る舞います。[ローテーション住宅プロキシ](https://quantumproxies.io/rotating-proxies)を通じて、そのプールは 200 以上の国にわたる 90M+ の IP をカバーし、以下のループはゼロローテーションロジックで各反復ごとに異なるオリジンを印刷します:

```js
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";

const agent = new HttpsProxyAgent("http://USER:PASS@residentialpremium.quantumproxies.io:8080");
const client = axios.create({ httpAgent: agent, httpsAgent: agent, proxy: false });

for (let i = 0; i < 3; i++) {
  const r = await client.get("https://httpbin.org/ip");
  console.log(r.data.origin); // a different exit IP each time
}
```

フローが複数のリクエストにまたがる場合 — ログイン、カートに追加、チェックアウト — リクエストごとのローテーションはセッションを壊します。プロキシユーザー名のスティッキーセッションパラメータは、設定されたウィンドウの間に 1 つの出口 IP を固定し、その後ローテーションします。同じエンドポイント、1 つの文字列変更。これを数千の同時リクエストにスケールする場合、axios ループから作業を移し、[大規模スクレイピングアーキテクチャ](https://quantumproxies.io/blog/large-scale-web-scraping-architecture)のガイドを読んで、キューイングと同時実行予算を確認してください。

## プロキシを通じてストリーミングレスポンス

ファイルや大きな JSON ペイロードをダウンロードするのは、エージェントがアタッチされた後はどのリクエストと同じです — `responseType: "stream"` を設定し、ボディをディスクにパイプします。プロキシは転送を透過的に処理するので、200MB のエクスポートがメモリにバッファリングされることはありません:

```js
import fs from "node:fs";

const r = await client.get("https://example.com/large.json", {
  responseType: "stream",
});
r.data.pipe(fs.createWriteStream("out.json"));
```

![httpbin.org/ipのページで示すNode.jsのプロキシの4つの間違い：axiosのproxy設定で自分の実IPが返るかハングする、デフォルトのagentのインポートで例外が出る、axiosでsocks5://を使うとプロトコルが一致しない、fetchがHTTP_PROXYを無視する。カードにはそれぞれの対策を示し、agentとproxyの設定を重複させないよう注意書きがある。](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335146/blog/generated/qp-b9-007-diag2.png)
*ほとんどの Node.js プロキシの失敗は 5 つの間違いに帰着します: axios の HTTPS バグ、デフォルトエージェントのインポート、二重プロキシ設定、間違った SOCKS スキーム、fetch が環境変数を読み取ることを期待すること。*

## よくある質問

### なぜ私の axios プロキシが機能しないのですか？

最も一般的な原因は、HTTP プロキシの背後にある HTTPS ターゲットです: axios の組み込み `proxy` 設定は CONNECT トンネルを開くことができず、実際の IP を返すか、ハングします。プロキシエージェントに切り替え — `HttpsProxyAgent` を `httpAgent` と `httpsAgent` にアタッチし、axios がプロキシを自分で処理しようとするのを止めるために `proxy: false` を設定します。

### axios は SOCKS5 プロキシをサポートしていますか？

ネイティブにはサポートしていません — `socks5://` URL を `proxy` 設定に渡すとプロトコルミスマッチエラーが発生します。`socks-proxy-agent` をインストールし、`SocksProxyAgent` を構築し、`httpAgent` と `httpsAgent` の両方に接続します。`socks5h://` スキームを使用して、DNS がマシンから漏れるのではなくプロキシ側で解決されるようにします。

### Node.js でネイティブ fetch にプロキシを使用するにはどうすればよいですか？

ネイティブ fetch にはプロキシオプションがなく、`HTTP_PROXY` 環境変数を無視します。undici の `ProxyAgent` を作成し、fetch 呼び出しで `dispatcher` オプションとして渡すか、`setGlobalDispatcher()` を一度呼び出してプロセス内のすべての fetch をプロキシします。undici は追加の設定なしで HTTPS CONNECT を正しく処理します。

### 環境変数で axios プロキシを設定するにはどうすればよいですか？

完全なプロキシ URL で `HTTP_PROXY`、`HTTPS_PROXY`、およびオプションで `NO_PROXY` をエクスポートします; axios はそれらを自動的に読み取ります。リクエストまたはインスタンスで `proxy: false` を設定して、axios が環境を無視するようにします。これは axios にのみ影響することを忘れないでください — undici とネイティブ fetch はそれらの変数を拾いません。

全体のストーリーはカードに収まります: axios はエージェントと `proxy: false` を必要とし、ネイティブ fetch は undici ディスパッチャーを必要とし、SOCKS は独自のエージェントを必要とし、ローテーションはループではなくゲートウェイに属します。配管を正しく行えば、最後の変数は IP の品質です — クリーンな住宅出口は、同じコードで 403 を受け取るフラグ付きデータセンター IP を通過します。

[最初のリクエストで通過する住宅プロキシを取得](https://quantumproxies.io/residential-proxies)
