Node.js 프록시 설정: Axios, Fetch, Undici 및 회전
axios 프록시 옵션은 HTTPS 대상에서 함정이며, 네이티브 fetch는 프록시 환경 변수를 완전히 무시합니다. 여기 axios, fetch 및 undici에서 작동하는 설정이 있습니다 — 에이전트, 인증, SOCKS5, 회전 및 스트리밍.
Node.js 요청을 프록시를 통해 라우팅하는 것은 간단해 보이지만 디버깅에 오후를 소비하게 됩니다. 그 이유는 대부분의 프로젝트에서 사용하는 세 가지 HTTP 클라이언트 — axios, Node 18에 글로벌로 제공된 네이티브 fetch, 그리고 기본 undici 라이브러리 — 각각 프록시를 다르게 처리하며, 기대한 대로 작동하지 않기 때문입니다. Axios는 문서화된 내장 proxy 구성을 가지고 있으며, Node 전용이며, HTTP 프록시 뒤의 HTTPS 대상에 대해 조용히 깨져 있습니다: 2020년부터 axios GitHub 추적기에 열려 있는 버그이며, 많은 추천을 받은 Stack Overflow 스레드를 유발했습니다. 한편 네이티브 fetch는 HTTP_PROXY 환경 변수를 무시하며 프록시 옵션이 전혀 없습니다. 이 가이드는 각 클라이언트에서 실제로 작동하는 설정, 인증, SOCKS5, 회전 및 스트리밍을 제공합니다.
Axios 프록시 구성 대 프록시 에이전트
Axios는 proxy 객체 — { host, port, auth } — 를 제공하며, 일반 HTTP 대상에 대해서는 잘 작동합니다. 함정은 HTTPS입니다: 대상이 https://이고 프록시가 HTTP를 사용할 때, axios는 CONNECT 터널을 열지 못하고 요청이 멈추거나 실제 IP로 돌아옵니다. 커뮤니티가 정한 해결책은 내장 구성을 완전히 우회하고 대신 axios에 프록시 에이전트를 제공한 다음, 두 메커니즘이 충돌하지 않도록 proxy: false를 설정하는 것입니다:
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@gate.quantumproxies.io:PORT");
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>" }
두 가지 세부 사항이 시간을 절약합니다. 첫째, 구조 분해된 { HttpsProxyAgent } 가져오기를 사용하세요 — 최근 버전은 이를 명명된 심볼로 내보내며, 기본 가져오기는 생성 시 예외를 발생시키는 객체를 제공합니다. 둘째, 프록시 URL 스킴은 프록시가 HTTPS 트래픽을 전달할 때에도 http://로 유지됩니다: 스킴은 프록시에 도달하는 방법을 설명하며, 대상에 대한 TLS는 터널 내부에서 실행됩니다. 동일한 실패 클래스가 Python에서도 나타납니다; requests에서도 작업하는 경우, 패턴은 우리의 ProxyError 및 SSLError 수정 가이드와 유사합니다.
인증 및 환경 변수
인증된 프록시는 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로 전환하는 순간 조용히 직접 연결됩니다.

undici로 네이티브 fetch 프록시하기
Node의 글로벌 fetch는 undici를 기반으로 하며, 프록시는 undici에 있습니다. ProxyAgent를 생성하고 이를 비표준 dispatcher 옵션으로 전달하세요 — 이것이 fetch를 프록시하는 현대적이고 종속성이 적은 방법이며, HTTPS CONNECT를 상자 밖에서 올바르게 처리합니다:
import { ProxyAgent } from "undici";
const dispatcher = new ProxyAgent({
uri: "http://gate.quantumproxies.io:PORT",
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 프록시 계획은 HTTP와 SOCKS5를 통해 동일한 게이트웨이를 노출하므로, 이는 새로운 구매가 아닌 스킴 전환입니다:
import axios from "axios";
import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://USER:PASS@gate.quantumproxies.io:PORT");
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 제거 — 는 더 이상 유지하지 않는 코드입니다. 회전 게이트웨이는 서버 측에서 매 요청마다 새로운 출구 IP를 할당하므로 하나의 엔드포인트가 전체 풀처럼 동작합니다. 회전 주거 프록시를 통해 그 풀은 90M+ IP를 200+ 국가에 걸쳐 포함하며, 아래 루프는 회전 로직 없이 각 반복마다 다른 출처를 출력합니다:
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://USER:PASS@gate.quantumproxies.io:PORT");
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
}
흐름이 여러 요청 — 로그인, 장바구니에 추가, 결제 — 에 걸쳐 있을 때, 요청당 회전은 세션을 깨뜨립니다. 프록시 사용자 이름의 고정 세션 매개변수는 설정된 시간 동안 하나의 출구 IP를 고정한 다음 회전합니다; 동일한 엔드포인트, 문자열 변경 하나. 이를 수천 개의 동시 요청으로 확장하려면, 작업을 axios 루프에서 벗어나게 하고 대규모 스크래핑 아키텍처에 대한 가이드를 읽어 대기열 및 동시성 예산을 확인하세요.
프록시를 통한 스트리밍 응답
파일이나 큰 JSON 페이로드를 다운로드하는 것은 에이전트가 연결된 후 모든 요청과 동일하게 작동합니다 — responseType: "stream"을 설정하고 본문을 디스크로 파이프합니다. 프록시는 전송을 투명하게 처리하므로 200MB 내보내기가 메모리에 버퍼링되지 않습니다:
import fs from "node:fs";
const r = await client.get("https://example.com/large.json", {
responseType: "stream",
});
r.data.pipe(fs.createWriteStream("out.json"));

자주 묻는 질문
왜 내 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를 통과합니다.