Node.js 애플리케이션을 개발할 때 파싱, 자동화 또는 API 작업을 위해 프록시 서버를 사용하는 경우가 많습니다. 이를 통해 지리적 제한을 우회하고 부하를 분산시키며 IP 차단을 피할 수 있습니다. 이 가이드에서는 Node.js에서 프록시를 설정하는 모든 방법을 기본부터 고급 기술인 회전 및 오류 처리까지 살펴보겠습니다.
Node.js에서 프록시 작업의 기본 개념
Node.js의 프록시 서버는 애플리케이션과 대상 서버 간의 중개자 역할을 합니다. 프록시를 통해 HTTP 요청을 보낼 때, 애플리케이션은 먼저 프록시 서버에 연결한 후 요청을 최종 주소로 전달합니다. 이를 통해 서버의 실제 IP 주소를 숨기고 프록시의 IP 주소를 사용할 수 있습니다.
Node.js에서는 사용되는 HTTP 요청 라이브러리에 따라 프록시 작업을 위한 몇 가지 기본 방법이 있습니다. 가장 인기 있는 옵션은 다음과 같습니다:
- 내장 http/https 모듈 — 추가 종속성 없이 기본 기능
- Axios — 편리한 API와 프로미스 지원을 갖춘 인기 라이브러리
- Got — TypeScript 지원이 뛰어난 현대적인 대안
- node-fetch — Node.js를 위한 Fetch API 구현
- request — 구식이지만 여전히 사용되는 라이브러리 (신규 프로젝트에 권장되지 않음)
프록시 서버는 다양한 프로토콜을 지원합니다. Node.js에서 주로 사용되는 프로토콜은 다음과 같습니다:
| 프로토콜 | 설명 | 용도 |
|---|---|---|
| HTTP | 암호화되지 않은 연결을 위한 기본 프로토콜 | 파싱, SSL 없이 API 작업 |
| HTTPS | SSL/TLS 암호화를 지원하는 프록시 | 안전한 연결, 보호된 API 작업 |
| SOCKS5 | 모든 유형의 트래픽을 위한 범용 프로토콜 | WebSocket, UDP, 복잡한 시나리오 |
파싱 및 자동화 작업을 위해 개발자들은 종종 주거용 프록시를 사용합니다. 이는 실제 가정 사용자 IP 주소를 가지고 있어 대상 웹사이트의 차단에 덜 걸리기 때문입니다.
내장 http/https 모듈을 통한 프록시 설정
Node.js는 HTTP 요청 작업을 위한 내장 모듈 http 및 https를 제공합니다. 프록시를 연결하기 위해 http-proxy-agent 또는 https-proxy-agent 라이브러리를 사용할 수 있습니다.
먼저 필요한 패키지를 설치하세요:
npm install http-proxy-agent https-proxy-agent
내장 모듈을 사용한 HTTP 프록시 사용 예제:
const http = require('http');
const { HttpProxyAgent } = require('http-proxy-agent');
// 프록시 설정
const proxyUrl = 'http://username:password@proxy-server.com:8080';
const agent = new HttpProxyAgent(proxyUrl);
// 요청 옵션
const options = {
hostname: 'api.example.com',
path: '/endpoint',
method: 'GET',
agent: agent,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
};
// 요청 실행
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('응답:', data);
});
});
req.on('error', (error) => {
console.error('요청 실패:', error.message);
});
req.end();
HTTPS 연결의 경우 https-proxy-agent를 사용하세요:
const https = require('https');
const { HttpsProxyAgent } = require('https-proxy-agent');
const proxyUrl = 'http://username:password@proxy-server.com:8080';
const agent = new HttpsProxyAgent(proxyUrl);
const options = {
hostname: 'api.example.com',
path: '/secure-endpoint',
method: 'GET',
agent: agent
};
https.get(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('안전한 응답:', data);
});
}).on('error', (error) => {
console.error('HTTPS 요청 실패:', error.message);
});
이 접근 방식은 요청에 대한 최대 제어를 제공하지만 프로미스 및 오류 처리를 위한 더 많은 코드를 요구합니다. 대부분의 작업에는 전문 라이브러리를 사용하는 것이 더 편리합니다.
Axios 라이브러리에서 프록시 작업
Axios는 Node.js에서 HTTP 요청을 위한 가장 인기 있는 라이브러리 중 하나입니다. 이 라이브러리는 프록시 설정을 위한 편리한 API를 제공하며 프로미스를 자동으로 처리합니다.
Axios 설치:
npm install axios
Axios에서 프록시의 기본 설정은 다음과 같습니다:
const axios = require('axios');
// 방법 1: 요청 구성에서 프록시 설정
axios.get('https://api.example.com/data', {
proxy: {
protocol: 'http',
host: 'proxy-server.com',
port: 8080,
auth: {
username: 'your-username',
password: 'your-password'
}
}
})
.then(response => {
console.log('데이터:', response.data);
})
.catch(error => {
console.error('오류:', error.message);
});
동일한 프록시 설정을 여러 번 사용할 경우, 미리 설정된 구성으로 Axios 인스턴스를 생성하는 것이 편리합니다:
const axios = require('axios');
// 프록시 설정으로 인스턴스 생성
const axiosWithProxy = axios.create({
proxy: {
protocol: 'http',
host: 'proxy-server.com',
port: 8080,
auth: {
username: 'your-username',
password: 'your-password'
}
},
timeout: 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
// 인스턴스 사용
async function fetchData() {
try {
const response = await axiosWithProxy.get('https://api.example.com/data');
console.log('응답:', response.data);
return response.data;
} catch (error) {
console.error('요청 실패:', error.message);
throw error;
}
}
fetchData();
CONNECT 메소드를 통해 HTTPS 프록시와 작업할 때는 추가 에이전트를 사용할 수 있습니다:
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const proxyUrl = 'http://username:password@proxy-server.com:8080';
const httpsAgent = new HttpsProxyAgent(proxyUrl);
const axiosInstance = axios.create({
httpsAgent: httpsAgent,
timeout: 15000
});
// 사용
axiosInstance.get('https://api.example.com/secure-data')
.then(response => console.log(response.data))
.catch(error => console.error(error.message));
Axios는 리디렉션을 자동으로 처리하고 로깅 및 오류 처리를 위한 인터셉터를 지원하므로 프록시를 적극적으로 사용하는 프로젝트에 적합한 선택입니다.
got 및 node-fetch에서 프록시 설정
Got는 Axios의 현대적인 대안으로, TypeScript 지원이 뛰어나고 고급 오류 처리 기능을 제공합니다. Node-fetch는 Node.js를 위한 표준 Fetch API를 구현합니다.
Got에서 프록시 작업
Got 및 필요한 에이전트 설치:
npm install got https-proxy-agent
Got에서 프록시 설정 예제:
const got = require('got');
const { HttpsProxyAgent } = require('https-proxy-agent');
const proxyUrl = 'http://username:password@proxy-server.com:8080';
const agent = {
https: new HttpsProxyAgent(proxyUrl)
};
// 프록시가 설정된 Got 인스턴스 생성
const gotWithProxy = got.extend({
agent: agent,
timeout: {
request: 10000
},
retry: {
limit: 3,
methods: ['GET', 'POST']
}
});
// 사용
async function fetchWithGot() {
try {
const response = await gotWithProxy('https://api.example.com/data');
console.log('응답:', JSON.parse(response.body));
} catch (error) {
console.error('Got 요청 실패:', error.message);
}
}
fetchWithGot();
node-fetch에서 프록시 작업
Node-fetch는 프록시 작업을 위해 에이전트를 명시적으로 설정해야 합니다:
npm install node-fetch https-proxy-agent
const fetch = require('node-fetch');
const { HttpsProxyAgent } = require('https-proxy-agent');
const proxyUrl = 'http://username:password@proxy-server.com:8080';
const agent = new HttpsProxyAgent(proxyUrl);
async function fetchWithProxy() {
try {
const response = await fetch('https://api.example.com/data', {
agent: agent,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
});
if (!response.ok) {
throw new Error(`HTTP 오류! 상태: ${response.status}`);
}
const data = await response.json();
console.log('데이터:', data);
return data;
} catch (error) {
console.error('Fetch 실패:', error.message);
throw error;
}
}
fetchWithProxy();
Got는 기본적으로 더 풍부한 기능(자동 재시도, 타임아웃, 오류 처리)을 제공하는 반면, node-fetch는 표준 Fetch API에 더 가깝고 브라우저 JavaScript에 익숙한 개발자에게 적합합니다.
socks-proxy-agent를 통한 SOCKS5 프록시 연결
SOCKS5는 HTTP/HTTPS보다 더 낮은 수준에서 작동하는 범용 프록시 프로토콜입니다. UDP 및 WebSocket 연결을 포함하여 모든 유형의 트래픽을 지원합니다. Node.js에서 SOCKS5를 사용하기 위해서는 socks-proxy-agent 라이브러리를 사용합니다.
필요한 패키지 설치:
npm install socks-proxy-agent
다양한 라이브러리와 함께 SOCKS5 프록시 사용 예제:
const { SocksProxyAgent } = require('socks-proxy-agent');
const https = require('https');
// 인증이 포함된 SOCKS5 프록시 설정
const proxyUrl = 'socks5://username:password@proxy-server.com:1080';
const agent = new SocksProxyAgent(proxyUrl);
const options = {
hostname: 'api.example.com',
path: '/endpoint',
method: 'GET',
agent: agent
};
https.get(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('SOCKS5 응답:', data);
});
}).on('error', (error) => {
console.error('SOCKS5 요청 실패:', error.message);
});
Axios와 함께 SOCKS5 사용:
const axios = require('axios');
const { SocksProxyAgent } = require('socks-proxy-agent');
const proxyUrl = 'socks5://username:password@proxy-server.com:1080';
const httpsAgent = new SocksProxyAgent(proxyUrl);
const httpAgent = new SocksProxyAgent(proxyUrl);
const axiosWithSocks = axios.create({
httpAgent: httpAgent,
httpsAgent: httpsAgent,
timeout: 15000
});
async function fetchViaSocks5() {
try {
const response = await axiosWithSocks.get('https://api.example.com/data');
console.log('SOCKS5를 통한 데이터:', response.data);
return response.data;
} catch (error) {
console.error('SOCKS5 요청 오류:', error.message);
throw error;
}
}
fetchViaSocks5();
SOCKS5 프록시는 비표준 프로토콜 작업이나 최대한의 유연성이 필요한 작업에 특히 유용합니다. 많은 공급자가 SOCKS5를 지원하는 모바일 프록시를 제공하여 모바일 API 작업을 위한 모바일 트래픽을 에뮬레이트할 수 있습니다.
부하 분산을 위한 프록시 회전 구현
대량의 데이터를 파싱하거나 하나의 IP에서 요청 수에 제한이 있는 API와 작업할 때는 프록시 회전을 사용해야 합니다. 이를 통해 여러 프록시 서버 간에 요청을 분산시켜 차단을 피할 수 있습니다.
간단한 프록시 회전 구현 예제:
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
class ProxyRotator {
constructor(proxyList) {
this.proxyList = proxyList;
this.currentIndex = 0;
}
// 순환 방식으로 다음 프록시 가져오기
getNextProxy() {
const proxy = this.proxyList[this.currentIndex];
this.currentIndex = (this.currentIndex + 1) % this.proxyList.length;
return proxy;
}
// 랜덤 프록시 가져오기
getRandomProxy() {
const randomIndex = Math.floor(Math.random() * this.proxyList.length);
return this.proxyList[randomIndex];
}
// 현재 프록시로 Axios 인스턴스 생성
createAxiosInstance(useRandom = false) {
const proxyUrl = useRandom ? this.getRandomProxy() : this.getNextProxy();
const agent = new HttpsProxyAgent(proxyUrl);
return axios.create({
httpsAgent: agent,
timeout: 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
}
}
// 프록시 목록
const proxyList = [
'http://user1:pass1@proxy1.example.com:8080',
'http://user2:pass2@proxy2.example.com:8080',
'http://user3:pass3@proxy3.example.com:8080',
'http://user4:pass4@proxy4.example.com:8080'
];
const rotator = new ProxyRotator(proxyList);
// 회전 사용
async function fetchWithRotation(url) {
const axiosInstance = rotator.createAxiosInstance();
try {
const response = await axiosInstance.get(url);
console.log('프록시로 성공');
return response.data;
} catch (error) {
console.error('요청 실패:', error.message);
throw error;
}
}
// 대량 파싱 예제
async function massiveParsing(urls) {
const results = [];
for (const url of urls) {
try {
const data = await fetchWithRotation(url);
results.push({ url, success: true, data });
// 요청 간 지연
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (error) {
results.push({ url, success: false, error: error.message });
}
}
return results;
}
// 파싱 실행
const urlsToParse = [
'https://api.example.com/data/1',
'https://api.example.com/data/2',
'https://api.example.com/data/3',
'https://api.example.com/data/4',
'https://api.example.com/data/5'
];
massiveParsing(urlsToParse)
.then(results => console.log('파싱 결과:', results))
.catch(error => console.error('파싱 오류:', error));
비활성 프록시를 자동으로 제외하고 프록시 상태를 추적하는 더 발전된 예제:
class AdvancedProxyRotator {
constructor(proxyList, maxFailures = 3) {
this.proxyList = proxyList.map(url => ({
url,
failures: 0,
active: true,
lastUsed: null
}));
this.maxFailures = maxFailures;
this.currentIndex = 0;
}
// 활성 프록시 가져오기
getActiveProxy() {
const activeProxies = this.proxyList.filter(p => p.active);
if (activeProxies.length === 0) {
throw new Error('활성 프록시가 없습니다');
}
// 가장 오랫동안 사용되지 않은 프록시 찾기
const proxy = activeProxies.reduce((oldest, current) => {
if (!oldest.lastUsed) return oldest;
if (!current.lastUsed) return current;
return current.lastUsed < oldest.lastUsed ? current : oldest;
});
proxy.lastUsed = Date.now();
return proxy;
}
// 프록시를 성공으로 표시
markSuccess(proxyUrl) {
const proxy = this.proxyList.find(p => p.url === proxyUrl);
if (proxy) {
proxy.failures = 0;
}
}
// 프록시를 실패로 표시
markFailure(proxyUrl) {
const proxy = this.proxyList.find(p => p.url === proxyUrl);
if (proxy) {
proxy.failures++;
if (proxy.failures >= this.maxFailures) {
proxy.active = false;
console.warn(`프록시 ${proxyUrl}는 ${proxy.failures}회 실패 후 비활성화되었습니다`);
}
}
}
// 회전으로 Axios 인스턴스 생성
async createAxiosInstance() {
const proxy = this.getActiveProxy();
const agent = new HttpsProxyAgent(proxy.url);
return {
instance: axios.create({
httpsAgent: agent,
timeout: 10000
}),
proxyUrl: proxy.url
};
}
// 프록시 통계 가져오기
getStats() {
return {
total: this.proxyList.length,
active: this.proxyList.filter(p => p.active).length,
inactive: this.proxyList.filter(p => !p.active).length,
proxies: this.proxyList.map(p => ({
url: p.url.replace(/\/\/.*@/, '//***@'), // 자격 증명 숨기기
active: p.active,
failures: p.failures
}))
};
}
}
// 고급 회전기 사용
const advancedRotator = new AdvancedProxyRotator(proxyList);
async function fetchWithAdvancedRotation(url) {
const { instance, proxyUrl } = await advancedRotator.createAxiosInstance();
try {
const response = await instance.get(url);
advancedRotator.markSuccess(proxyUrl);
return response.data;
} catch (error) {
advancedRotator.markFailure(proxyUrl);
throw error;
}
}
// 주기적인 통계 출력
setInterval(() => {
console.log('프록시 통계:', advancedRotator.getStats());
}, 30000);
이러한 시스템은 비활성 프록시를 자동으로 제외하고 활성 서버 간에 부하를 고르게 분산시킵니다. 이는 대량의 데이터를 처리할 때 매우 중요합니다.
오류 처리 및 자동 프록시 전환
프록시 작업 중에는 타임아웃, 연결 거부, 대상 서버의 차단과 같은 오류가 발생할 수 있습니다. 오류를 올바르게 처리하고 다른 프록시로 자동 전환하는 것은 애플리케이션의 신뢰성을 높입니다.
자동 재시도 및 프록시 전환 시스템 구현 예제:
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
class ResilientProxyClient {
constructor(proxyList, maxRetries = 3) {
this.proxyList = proxyList;
this.maxRetries = maxRetries;
this.currentProxyIndex = 0;
}
// 다음 프록시 가져오기
getNextProxy() {
const proxy = this.proxyList[this.currentProxyIndex];
this.currentProxyIndex = (this.currentProxyIndex + 1) % this.proxyList.length;
return proxy;
}
// 오류 유형 결정
isRetryableError(error) {
// 요청을 재시도해야 하는 오류
const retryableCodes = ['ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED'];
const retryableStatuses = [408, 429, 500, 502, 503, 504];
if (error.code && retryableCodes.includes(error.code)) {
return true;
}
if (error.response && retryableStatuses.includes(error.response.status)) {
return true;
}
return false;
}
// 자동 재시도와 함께 요청 실행
async request(url, options = {}, attempt = 1) {
const proxyUrl = this.getNextProxy();
const agent = new HttpsProxyAgent(proxyUrl);
const config = {
...options,
httpsAgent: agent,
timeout: 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
...options.headers
}
};
try {
console.log(`시도 ${attempt}/${this.maxRetries} 프록시: ${proxyUrl.replace(/\/\/.*@/, '//***@')}`);
const response = await axios.get(url, config);
console.log(`시도 ${attempt} 성공`);
return response.data;
} catch (error) {
console.error(`시도 ${attempt} 실패: ${error.message}`);
// 재시도 한계에 도달한 경우
if (attempt >= this.maxRetries) {
console.error(`URL ${url}에 대해 최대 재시도(${this.maxRetries})에 도달했습니다`);
throw error;
}
// 재시도할 수 없는 오류인 경우
if (!this.isRetryableError(error)) {
console.error(`재시도할 수 없는 오류: ${error.message}`);
throw error;
}
// 재시도 전 지연
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
console.log(`재시도 전 ${delay}ms 대기...`);
await new Promise(resolve => setTimeout(resolve, delay));
// 다음 프록시로 재귀적 재시도
return this.request(url, options, attempt + 1);
}
}
// 오류 처리와 함께 URL 배치 처리
async batchRequest(urls, concurrency = 3) {
const results = [];
const queue = [...urls];
const active = [];
while (queue.length > 0 || active.length > 0) {
// 동시성 한도에 도달할 때까지 새로운 작업 시작
while (active.length < concurrency && queue.length > 0) {
const url = queue.shift();
const promise = this.request(url)
.then(data => ({ url, success: true, data }))
.catch(error => ({ url, success: false, error: error.message }))
.finally(() => {
const index = active.indexOf(promise);
if (index > -1) active.splice(index, 1);
});
active.push(promise);
}
// 적어도 하나의 작업이 완료될 때까지 대기
if (active.length > 0) {
const result = await Promise.race(active);
results.push(result);
}
}
return results;
}
}
// 사용 예
const proxyList = [
'http://user1:pass1@proxy1.example.com:8080',
'http://user2:pass2@proxy2.example.com:8080',
'http://user3:pass3@proxy3.example.com:8080'
];
const client = new ResilientProxyClient(proxyList, 3);
// 단일 요청
client.request('https://api.example.com/data')
.then(data => console.log('데이터:', data))
.catch(error => console.error('최종 오류:', error.message));
// 배치 처리
const urls = [
'https://api.example.com/data/1',
'https://api.example.com/data/2',
'https://api.example.com/data/3',
'https://api.example.com/data/4',
'https://api.example.com/data/5'
];
client.batchRequest(urls, 3)
.then(results => {
const successful = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
console.log(`완료: ${successful} 성공, ${failed} 실패`);
console.log('결과:', results);
});
이 구현은 다음을 포함합니다:
- 오류 발생 시 다음 프록시로 자동 전환
- 재시도 간의 지연(1초, 2초, 4초, 8초, 최대 10초)
- 재시도 여부를 결정하기 위한 오류 유형 식별
- 배치 처리 시 동시성 제어
- 디버깅을 위한 자세한 로깅
최고의 관행 및 성능 최적화
Node.js 애플리케이션에서 프록시 작업을 수행할 때 안정성과 성능을 보장하기 위해 다음 권장 사항을 따르세요:
1. 연결 관리
각 요청마다 새로운 HTTP 에이전트를 생성하는 대신 재사용하세요. 이는 연결 설정에 대한 오버헤드를 줄입니다:
const { HttpsProxyAgent } = require('https-proxy-agent');
// 나쁜 예: 각 요청에 대한 에이전트 생성
async function badExample(url) {
const agent = new HttpsProxyAgent(proxyUrl);
return axios.get(url, { httpsAgent: agent });
}
// 좋은 예: 에이전트 재사용
const agent = new HttpsProxyAgent(proxyUrl);
const axiosInstance = axios.create({
httpsAgent: agent,
httpAgent: agent
});
async function goodExample(url) {
return axiosInstance.get(url);
}
2. 타임아웃 설정
애플리케이션이 멈추지 않도록 합리적인 타임아웃을 항상 설정하세요:
const axiosInstance = axios.create({
httpsAgent: agent,
timeout: 10000, // 전체 타임아웃
// Got의 세부 타임아웃 설정
// timeout: {
// lookup: 1000, // DNS 조회
// connect: 2000, // 프록시 연결
// secureConnect: 2000, // SSL 핸드쉐이크
// socket: 5000, // 소켓 비활성
// response: 3000, // 첫 번째 바이트 응답 대기
// send: 10000, // 요청 전송
// request: 15000 // 전체 요청
// }
});
3. 동시성 제어
과부하를 방지하기 위해 동시 요청 수를 제한하세요:
const pLimit = require('p-limit');
// 동시 요청을 5개로 제한
const limit = pLimit(5);
async function processUrls(urls) {
const promises = urls.map(url =>
limit(() => axiosInstance.get(url))
);
return Promise.allSettled(promises);
}
4. User-Agent 회전
프록시 회전과 함께 User-Agent 회전을 결합하여 더 높은 익명성을 확보하세요:
const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0'
];
function getRandomUserAgent() {
return userAgents[Math.floor(Math.random() * userAgents.length)];
}
async function fetchWithRandomUA(url) {
return axiosInstance.get(url, {
headers: {
'User-Agent': getRandomUserAgent()
}
});
}
5. 모니터링 및 로깅
프록시 성능을 추적하기 위한 모니터링 시스템을 구현하세요:
class ProxyMonitor {
constructor() {
this.stats = new Map();
}
recordRequest(proxyUrl, success, responseTime) {
if (!this.stats.has(proxyUrl)) {
this.stats.set(proxyUrl, {
total: 0,
success: 0,
failed: 0,
totalResponseTime: 0,
avgResponseTime: 0
});
}
const stat = this.stats.get(proxyUrl);
stat.total++;
if (success) {
stat.success++;
stat.totalResponseTime += responseTime;
stat.avgResponseTime = stat.totalResponseTime / stat.success;
} else {
stat.failed++;
}
}
getReport() {
const report = [];
this.stats.forEach((stat, proxyUrl) => {
report.push({
proxy: proxyUrl.replace(/\/\/.*@/, '//***@'),
successRate: ((stat.success / stat.total) * 100).toFixed(2) + '%',
avgResponseTime: stat.avgResponseTime.toFixed(0) + 'ms',
total: stat.total,
success: stat.success,
failed: stat.failed
});
});
return report;
}
}
const monitor = new ProxyMonitor();
// 모니터링과 함께 요청 래핑
async function monitoredRequest(url, proxyUrl) {
const startTime = Date.now();
try {
const response = await axiosInstance.get(url);
const responseTime = Date.now() - startTime;
monitor.recordRequest(proxyUrl, true, responseTime);
return response.data;
} catch (error) {
const responseTime = Date.now() - startTime;
monitor.recordRequest(proxyUrl, false, responseTime);
throw error;
}
}
// 주기적인 보고
setInterval(() => {
console.table(monitor.getReport());
}, 60000);
6. 프록시 유형 선택
작업에 따라 프록시 유형을 선택하세요:
| 작업 | 추천 유형 | 이유 |
|---|---|---|
| 공공 데이터 대량 파싱 | 데이터 센터 프록시 | 높은 속도, 낮은 가격 |
| 소셜 미디어 및 보호된 플랫폼 작업 | 주거용 프록시 | 실제 IP, 낮은 차단 위험 |
| 모바일 트래픽 에뮬레이션 | 모바일 프록시 | 모바일 운영자의 IP |
| 비표준 프로토콜 작업 | SOCKS5 프록시 | 모든 트래픽 지원 |
높은 수준의 익명성과 최소한의 차단 위험이 필요한 작업에는 주거용 프록시를 사용하는 것이 좋습니다. 대량의 데이터를 고속으로 파싱하려면 데이터 센터 프록시가 적합합니다.
7. 자격 증명 보안
절대 코드에 프록시 자격 증명을 저장하지 마세요. 환경 변수를 사용하세요:
// .env 파일
PROXY_HOST=proxy-server.com
PROXY_PORT=8080
PROXY_USERNAME=your-username
PROXY_PASSWORD=your-password
// 코드에서
require('dotenv').config();
const proxyUrl = `http://${process.env.PROXY_USERNAME}:${process.env.PROXY_PASSWORD}@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
// 또는 프록시 목록의 경우
const proxyList = process.env.PROXY_LIST.split(',').map(proxy => proxy.trim());
결론
Node.js 애플리케이션에서 프록시 설정은 파싱, 자동화 및 외부 API 통합 작업을 하는 개발자에게 중요한 기술입니다. 이 가이드에서는 내장 모듈을 통한 기본 설정부터 회전, 오류 처리 및 모니터링과 같은 고급 기술까지 프록시 작업의 모든 주요 방법을 살펴보았습니다.
기억해야 할 주요 사항:
- 작업에 따라 HTTP 요청 라이브러리를 선택하세요: Axios는 범용성, Got는 TypeScript 프로젝트, node-fetch는 브라우저 API와의 호환성을 위해 사용하세요
- 비표준 프로토콜 작업 및 최대 유연성을 위해 SOCKS5 프록시를 사용하세요
- 부하 분산 및 차단 방지를 위해 프록시 회전을 구현하세요
- 자동 재시도 및 프록시 전환을 포함한 오류 처리 시스템을 구현하세요
- 프록시 성능을 모니터링하고 비활성 프록시를 자동으로 제외하세요
- HTTP 에이전트를 재사용하고 합리적인 타임아웃을 설정하세요
- 코드에 자격 증명을 저장하지 말고 환경 변수에 저장하세요
Node.js 애플리케이션에 적합한 프록시를 선택할 때 작업의 특성을 고려하세요. 보호된 플랫폼을 파싱하고 IP 평판에 민감한 API와 작업할 때는 주거용 프록시를 사용하는 것이 좋습니다. 이는 실제 가정 사용자 IP 주소를 사용하여 높은 수준의 익명성과 최소한의 차단 위험을 보장합니다.