内置 fetch 与 undici#
Node 的全局 fetch 基于 undici。可以通过 dispatcher 选项为每次请求传入 ProxyAgent,也可以调用一次 setGlobalDispatcher 完成全局设置。
import { fetch, ProxyAgent, setGlobalDispatcher } from "undici";
const proxy = new ProxyAgent("http://USER-cc-us:[email protected]:9000");
// 按请求设置
const res = await fetch("https://api.ipify.org", { dispatcher: proxy });
console.log(await res.text());
// 或进行全局设置,应用于该进程中的所有 fetch
setGlobalDispatcher(proxy);ProxyAgent 会建立连接池,因此连续请求可能复用同一连接,进而沿用同一出口。若希望每次请求都使用新出口,请以 pipelining: 0 和 connections: 1 创建 agent;也可以直接为每个逻辑会话使用不同的 -sid-。
axios#
axios 自带的 proxy 选项无法可靠地为 HTTPS 建立隧道;标准做法是使用 https-proxy-agent 提供的 agent,并设置 proxy: false。
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://USER-cc-de-city-berlin-sid-cart42-ttl-15m:[email protected]:9000");
const client = axios.create({ httpsAgent: agent, httpAgent: agent, proxy: false, timeout: 30000 });
const { data } = await client.get("https://api.ipify.org");
console.log(data);got#
import got from "got";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://USER-cc-us:[email protected]:9000");
const body = await got("https://api.ipify.org", { agent: { https: agent, http: agent }, timeout: { request: 30000 } }).text();
console.log(body);SOCKS5#
import { SocksProxyAgent } from "socks-proxy-agent";
// socks5h 在出口端解析目标地址
const agent = new SocksProxyAgent("socks5h://USER-cc-us:[email protected]:9001");
const res = await fetch("https://api.ipify.org", { dispatcher: undefined, agent }); // node-fetch 风格的客户端接收 `agent`环境变量#
undici 默认不读取 HTTPS_PROXY。较新的 undici 版本提供了能够读取它的 EnvHttpProxyAgent;将其设为全局 dispatcher 后,整个进程都会通过代理,包括基于 fetch 构建的第三方库。
import { EnvHttpProxyAgent, setGlobalDispatcher } from "undici";
// HTTPS_PROXY=http://USER-cc-us:[email protected]:9000 NO_PROXY=localhost node app.js
setGlobalDispatcher(new EnvHttpProxyAgent());并发与轮换#
- 每个粘性会话使用一个
ProxyAgent(各自采用不同的-sid-),并由该会话的所有请求共享。 - 如需大范围轮换,可以保留一个 agent 但禁用连接复用;也可以运行 N 个 agent,分别使用 N 个会话 ID,再以轮询方式分配请求。
- 留意
UND_ERR_SOCKET和ECONNRESET:它们表示住宅出口已经失效。重试一次,下一个连接会选择其他出口。
大家常问的问题#
为什么 axios 在访问 HTTPS 时会忽略我的代理?
其内置代理功能对 CONNECT 隧道的支持有限。请将 https-proxy-agent 用作 httpsAgent,并设置 proxy: false,避免 axios 自行处理代理。
可以只让部分请求走代理吗?
可以。只需在需要代理的请求中传入 dispatcher 或 agent,其他请求保持不变;除非调用 setGlobalDispatcher,否则任何设置都不是全局的。