Quay lại blog

Cài đặt proxy trong ứng dụng Node.js: hướng dẫn đầy đủ với ví dụ mã

Hướng dẫn chi tiết về việc tích hợp proxy vào Node.js: từ cấu hình cơ bản đến các kỹ thuật nâng cao về xoay vòng IP và xử lý lỗi.

📅14 tháng 2, 2026
```html

Khi phát triển các ứng dụng Node.js cho việc phân tích, tự động hóa hoặc làm việc với API, thường có nhu cầu sử dụng máy chủ proxy. Điều này cho phép vượt qua các hạn chế địa lý, phân phối tải và tránh bị chặn theo IP. Trong hướng dẫn này, chúng ta sẽ xem xét tất cả các cách cài đặt proxy trong Node.js — từ cơ bản đến các kỹ thuật nâng cao với xoay vòng và xử lý lỗi.

Các khái niệm cơ bản về làm việc với proxy trong Node.js

Máy chủ proxy trong Node.js hoạt động như một trung gian giữa ứng dụng của bạn và máy chủ đích. Khi bạn gửi yêu cầu HTTP qua proxy, ứng dụng của bạn trước tiên kết nối với máy chủ proxy, sau đó máy chủ này chuyển tiếp yêu cầu đến địa chỉ cuối. Điều này cho phép ẩn địa chỉ IP thực của máy chủ của bạn và sử dụng địa chỉ IP của proxy.

Trong Node.js có một số cách cơ bản để làm việc với proxy tùy thuộc vào thư viện được sử dụng cho các yêu cầu HTTP. Các tùy chọn phổ biến nhất:

  • Các mô-đun tích hợp http/https — chức năng cơ bản không cần phụ thuộc thêm
  • Axios — thư viện phổ biến với API thân thiện và hỗ trợ promise
  • Got — lựa chọn hiện đại với hỗ trợ TypeScript
  • node-fetch — triển khai Fetch API cho Node.js
  • request — thư viện đã lỗi thời nhưng vẫn được sử dụng (không khuyến nghị cho các dự án mới)

Các máy chủ proxy hỗ trợ nhiều giao thức khác nhau. Để làm việc với Node.js, thường sử dụng:

Giao thức Mô tả Ứng dụng
HTTP Giao thức cơ bản cho các kết nối không mã hóa Phân tích, làm việc với API không SSL
HTTPS Proxy hỗ trợ mã hóa SSL/TLS Kết nối an toàn, làm việc với API bảo mật
SOCKS5 Giao thức đa năng cho bất kỳ loại lưu lượng nào WebSocket, UDP, kịch bản phức tạp

Đối với các nhiệm vụ phân tích và tự động hóa, các nhà phát triển thường sử dụng proxy dân cư, vì chúng có địa chỉ IP thực của người dùng gia đình và ít bị chặn bởi các trang web đích hơn.

Cài đặt proxy qua mô-đun http/https tích hợp

Node.js cung cấp các mô-đun tích hợp httphttps để làm việc với các yêu cầu HTTP. Để kết nối proxy, bạn có thể sử dụng thư viện http-proxy-agent hoặc https-proxy-agent.

Đầu tiên, hãy cài đặt các gói cần thiết:

npm install http-proxy-agent https-proxy-agent

Ví dụ sử dụng proxy HTTP với mô-đun tích hợp:

const http = require('http');
const { HttpProxyAgent } = require('http-proxy-agent');

// Cài đặt proxy
const proxyUrl = 'http://username:password@proxy-server.com:8080';
const agent = new HttpProxyAgent(proxyUrl);

// Tùy chọn yêu cầu
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'
  }
};

// Thực hiện yêu cầu
const req = http.request(options, (res) => {
  let data = '';
  
  res.on('data', (chunk) => {
    data += chunk;
  });
  
  res.on('end', () => {
    console.log('Phản hồi:', data);
  });
});

req.on('error', (error) => {
  console.error('Yêu cầu thất bại:', error.message);
});

req.end();

Đối với các kết nối HTTPS, hãy sử dụng 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('Phản hồi an toàn:', data);
  });
}).on('error', (error) => {
  console.error('Yêu cầu HTTPS thất bại:', error.message);
});

Cách tiếp cận này cung cấp kiểm soát tối đa đối với các yêu cầu, nhưng yêu cầu nhiều mã hơn để xử lý các promise và lỗi. Đối với hầu hết các nhiệm vụ, việc sử dụng các thư viện chuyên dụng sẽ tiện lợi hơn.

Làm việc với proxy trong thư viện Axios

Axios — một trong những thư viện phổ biến nhất cho các yêu cầu HTTP trong Node.js. Nó cung cấp một API thân thiện để cài đặt proxy và tự động xử lý các promise.

Cài đặt Axios:

npm install axios

Cài đặt cơ bản proxy trong Axios trông như sau:

const axios = require('axios');

// Cách 1: Cài đặt proxy trong cấu hình yêu cầu
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('Dữ liệu:', response.data);
})
.catch(error => {
  console.error('Lỗi:', error.message);
});

Để sử dụng lại cùng một cấu hình proxy nhiều lần, bạn có thể tạo một phiên bản Axios với cấu hình đã được thiết lập sẵn:

const axios = require('axios');

// Tạo một phiên bản với cài đặt proxy
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'
  }
});

// Sử dụng phiên bản
async function fetchData() {
  try {
    const response = await axiosWithProxy.get('https://api.example.com/data');
    console.log('Phản hồi:', response.data);
    return response.data;
  } catch (error) {
    console.error('Yêu cầu thất bại:', error.message);
    throw error;
  }
}

fetchData();

Để làm việc với proxy HTTPS qua phương thức CONNECT, bạn có thể sử dụng các tác nhân bổ sung:

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
});

// Sử dụng
axiosInstance.get('https://api.example.com/secure-data')
  .then(response => console.log(response.data))
  .catch(error => console.error(error.message));

Axios tự động xử lý việc chuyển hướng và hỗ trợ các interceptor để ghi lại và xử lý lỗi, điều này làm cho nó trở thành lựa chọn tuyệt vời cho các dự án sử dụng proxy nhiều.

Cài đặt proxy trong got và node-fetch

Got — lựa chọn hiện đại cho Axios với hỗ trợ TypeScript tuyệt vời và khả năng xử lý lỗi nâng cao. Node-fetch triển khai Fetch API tiêu chuẩn cho Node.js.

Làm việc với proxy trong Got

Cài đặt Got và các tác nhân cần thiết:

npm install got https-proxy-agent

Ví dụ về cài đặt proxy trong 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)
};

// Tạo một phiên bản Got với proxy
const gotWithProxy = got.extend({
  agent: agent,
  timeout: {
    request: 10000
  },
  retry: {
    limit: 3,
    methods: ['GET', 'POST']
  }
});

// Sử dụng
async function fetchWithGot() {
  try {
    const response = await gotWithProxy('https://api.example.com/data');
    console.log('Phản hồi:', JSON.parse(response.body));
  } catch (error) {
    console.error('Yêu cầu Got thất bại:', error.message);
  }
}

fetchWithGot();

Làm việc với proxy trong node-fetch

Node-fetch yêu cầu cấu hình tác nhân rõ ràng để làm việc với proxy:

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(`Lỗi HTTP! trạng thái: ${response.status}`);
    }
    
    const data = await response.json();
    console.log('Dữ liệu:', data);
    return data;
  } catch (error) {
    console.error('Fetch thất bại:', error.message);
    throw error;
  }
}

fetchWithProxy();

Got cung cấp nhiều chức năng phong phú hơn ngay từ đầu (tự động thử lại, thời gian chờ, xử lý lỗi), trong khi node-fetch gần gũi hơn với Fetch API tiêu chuẩn và phù hợp cho các nhà phát triển quen thuộc với JavaScript trên trình duyệt.

Kết nối proxy SOCKS5 qua socks-proxy-agent

SOCKS5 — giao thức proxy đa năng, hoạt động ở mức thấp hơn so với HTTP/HTTPS. Nó hỗ trợ bất kỳ loại lưu lượng nào, bao gồm cả UDP và kết nối WebSocket. Để làm việc với SOCKS5 trong Node.js, bạn có thể sử dụng thư viện socks-proxy-agent.

Cài đặt các gói cần thiết:

npm install socks-proxy-agent

Ví dụ sử dụng proxy SOCKS5 với các thư viện khác nhau:

const { SocksProxyAgent } = require('socks-proxy-agent');
const https = require('https');

// Cài đặt proxy SOCKS5 với xác thực
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('Phản hồi SOCKS5:', data);
  });
}).on('error', (error) => {
  console.error('Yêu cầu SOCKS5 thất bại:', error.message);
});

Sử dụng SOCKS5 với Axios:

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('Dữ liệu qua SOCKS5:', response.data);
    return response.data;
  } catch (error) {
    console.error('Lỗi yêu cầu SOCKS5:', error.message);
    throw error;
  }
}

fetchViaSocks5();

Proxy SOCKS5 đặc biệt hữu ích cho các nhiệm vụ yêu cầu làm việc với các giao thức không chuẩn hoặc khi cần tính linh hoạt tối đa. Nhiều nhà cung cấp cung cấp proxy di động với hỗ trợ SOCKS5, cho phép mô phỏng lưu lượng di động để làm việc với các API di động.

Thực hiện xoay vòng proxy để phân phối tải

Khi phân tích một lượng lớn dữ liệu hoặc làm việc với API có giới hạn số lượng yêu cầu từ một IP, cần sử dụng xoay vòng proxy. Điều này cho phép phân phối các yêu cầu giữa nhiều máy chủ proxy và tránh bị chặn.

Ví dụ về việc thực hiện xoay vòng proxy đơn giản:

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

class ProxyRotator {
  constructor(proxyList) {
    this.proxyList = proxyList;
    this.currentIndex = 0;
  }
  
  // Lấy proxy tiếp theo theo nguyên tắc vòng tròn
  getNextProxy() {
    const proxy = this.proxyList[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.proxyList.length;
    return proxy;
  }
  
  // Lấy proxy ngẫu nhiên
  getRandomProxy() {
    const randomIndex = Math.floor(Math.random() * this.proxyList.length);
    return this.proxyList[randomIndex];
  }
  
  // Tạo một phiên bản Axios với proxy hiện tại
  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'
      }
    });
  }
}

// Danh sách proxy
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);

// Sử dụng xoay vòng
async function fetchWithRotation(url) {
  const axiosInstance = rotator.createAxiosInstance();
  
  try {
    const response = await axiosInstance.get(url);
    console.log('Thành công với proxy');
    return response.data;
  } catch (error) {
    console.error('Yêu cầu thất bại:', error.message);
    throw error;
  }
}

// Ví dụ về phân tích hàng loạt với xoay vòng
async function massiveParsing(urls) {
  const results = [];
  
  for (const url of urls) {
    try {
      const data = await fetchWithRotation(url);
      results.push({ url, success: true, data });
      
      // Đợi giữa các yêu cầu
      await new Promise(resolve => setTimeout(resolve, 1000));
    } catch (error) {
      results.push({ url, success: false, error: error.message });
    }
  }
  
  return results;
}

// Khởi động phân tích
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('Kết quả phân tích:', results))
  .catch(error => console.error('Lỗi phân tích:', error));

Ví dụ nâng cao hơn với việc theo dõi trạng thái của proxy và tự động loại trừ các proxy không hoạt động:

class AdvancedProxyRotator {
  constructor(proxyList, maxFailures = 3) {
    this.proxyList = proxyList.map(url => ({
      url,
      failures: 0,
      active: true,
      lastUsed: null
    }));
    this.maxFailures = maxFailures;
    this.currentIndex = 0;
  }
  
  // Lấy proxy hoạt động
  getActiveProxy() {
    const activeProxies = this.proxyList.filter(p => p.active);
    
    if (activeProxies.length === 0) {
      throw new Error('Không có proxy hoạt động nào');
    }
    
    // Tìm proxy chưa được sử dụng lâu nhất
    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;
  }
  
  // Đánh dấu proxy là thành công
  markSuccess(proxyUrl) {
    const proxy = this.proxyList.find(p => p.url === proxyUrl);
    if (proxy) {
      proxy.failures = 0;
    }
  }
  
  // Đánh dấu proxy là thất bại
  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(`Proxy ${proxyUrl} đã bị vô hiệu hóa sau ${proxy.failures} lần thất bại`);
      }
    }
  }
  
  // Tạo một phiên bản Axios với xoay vòng
  async createAxiosInstance() {
    const proxy = this.getActiveProxy();
    const agent = new HttpsProxyAgent(proxy.url);
    
    return {
      instance: axios.create({
        httpsAgent: agent,
        timeout: 10000
      }),
      proxyUrl: proxy.url
    };
  }
  
  // Lấy thống kê proxy
  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(/\/\/.*@/, '//***@'), // Ẩn thông tin xác thực
        active: p.active,
        failures: p.failures
      }))
    };
  }
}

// Sử dụng bộ xoay vòng proxy nâng cao
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;
  }
}

// Xuất báo cáo định kỳ
setInterval(() => {
  console.log('Thống kê proxy:', advancedRotator.getStats());
}, 30000);

Hệ thống này tự động loại trừ các proxy không hoạt động khỏi xoay vòng và phân phối tải đồng đều giữa các máy chủ hoạt động. Điều này cực kỳ quan trọng khi làm việc với một lượng lớn dữ liệu.

Xử lý lỗi và tự động chuyển đổi proxy

Khi làm việc với proxy, không thể tránh khỏi các lỗi: thời gian chờ, từ chối kết nối, chặn từ máy chủ đích. Xử lý lỗi đúng cách và tự động chuyển đổi sang proxy khác nâng cao độ tin cậy của ứng dụng.

Ví dụ về việc triển khai hệ thống với các lần thử lại tự động và chuyển đổi proxy:

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;
  }
  
  // Lấy proxy tiếp theo
  getNextProxy() {
    const proxy = this.proxyList[this.currentProxyIndex];
    this.currentProxyIndex = (this.currentProxyIndex + 1) % this.proxyList.length;
    return proxy;
  }
  
  // Xác định loại lỗi
  isRetryableError(error) {
    // Các lỗi mà nên thử lại yêu cầu
    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;
  }
  
  // Thực hiện yêu cầu với các lần thử lại tự động
  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(`Cố gắng ${attempt}/${this.maxRetries} với proxy: ${proxyUrl.replace(/\/\/.*@/, '//***@')}`);
      const response = await axios.get(url, config);
      console.log(`Thành công ở lần cố gắng ${attempt}`);
      return response.data;
    } catch (error) {
      console.error(`Lần cố gắng ${attempt} thất bại: ${error.message}`);
      
      // Nếu đã đạt giới hạn thử lại
      if (attempt >= this.maxRetries) {
        console.error(`Đã đạt giới hạn thử lại (${this.maxRetries}) cho ${url}`);
        throw error;
      }
      
      // Nếu lỗi không thể thử lại
      if (!this.isRetryableError(error)) {
        console.error(`Lỗi không thể thử lại: ${error.message}`);
        throw error;
      }
      
      // Thời gian chờ theo cấp số nhân trước khi thử lại
      const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
      console.log(`Đợi ${delay}ms trước khi thử lại...`);
      await new Promise(resolve => setTimeout(resolve, delay));
      
      // Thử lại đệ quy với proxy tiếp theo
      return this.request(url, options, attempt + 1);
    }
  }
  
  // Xử lý hàng loạt URL với xử lý lỗi
  async batchRequest(urls, concurrency = 3) {
    const results = [];
    const queue = [...urls];
    const active = [];
    
    while (queue.length > 0 || active.length > 0) {
      // Khởi động các nhiệm vụ mới cho đến khi đạt giới hạn đồng thời
      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);
      }
      
      // Đợi ít nhất một nhiệm vụ hoàn thành
      if (active.length > 0) {
        const result = await Promise.race(active);
        results.push(result);
      }
    }
    
    return results;
  }
}

// Sử dụng
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);

// Yêu cầu đơn
client.request('https://api.example.com/data')
  .then(data => console.log('Dữ liệu:', data))
  .catch(error => console.error('Lỗi cuối cùng:', error.message));

// Xử lý hàng loạt
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(`Hoàn thành: ${successful} thành công, ${failed} thất bại`);
    console.log('Kết quả:', results);
  });

Triển khai này bao gồm:

  • Tự động chuyển đổi sang proxy tiếp theo khi có lỗi
  • Thời gian chờ theo cấp số nhân giữa các lần thử lại (1s, 2s, 4s, 8s, tối đa 10s)
  • Xác định loại lỗi để quyết định có thử lại hay không
  • Kiểm soát đồng thời khi xử lý hàng loạt
  • Ghi lại chi tiết để gỡ lỗi

Các thực tiễn tốt nhất và tối ưu hóa hiệu suất

Khi làm việc với proxy trong các ứng dụng Node.js, bạn nên tuân theo các khuyến nghị sau để đảm bảo tính ổn định và hiệu suất:

1. Quản lý kết nối

Tái sử dụng các tác nhân HTTP thay vì tạo mới cho mỗi yêu cầu. Điều này giảm overhead khi thiết lập kết nối:

const { HttpsProxyAgent } = require('https-proxy-agent');

// Xấu: tạo tác nhân cho mỗi yêu cầu
async function badExample(url) {
  const agent = new HttpsProxyAgent(proxyUrl);
  return axios.get(url, { httpsAgent: agent });
}

// Tốt: tái sử dụng tác nhân
const agent = new HttpsProxyAgent(proxyUrl);
const axiosInstance = axios.create({
  httpsAgent: agent,
  httpAgent: agent
});

async function goodExample(url) {
  return axiosInstance.get(url);
}

2. Cài đặt thời gian chờ

Luôn đặt thời gian chờ hợp lý để tránh treo ứng dụng:

const axiosInstance = axios.create({
  httpsAgent: agent,
  timeout: 10000, // Thời gian chờ chung
  // Cài đặt chi tiết thời gian chờ cho Got
  // timeout: {
  //   lookup: 1000,    // Tìm kiếm DNS
  //   connect: 2000,   // Kết nối với proxy
  //   secureConnect: 2000, // Bắt tay SSL
  //   socket: 5000,    // Không hoạt động của socket
  //   response: 3000,  // Chờ byte đầu tiên của phản hồi
  //   send: 10000,     // Gửi yêu cầu
  //   request: 15000   // Toàn bộ yêu cầu
  // }
});

3. Kiểm soát đồng thời

Giới hạn số lượng yêu cầu đồng thời để tránh quá tải:

const pLimit = require('p-limit');

// Giới hạn đến 5 yêu cầu đồng thời
const limit = pLimit(5);

async function processUrls(urls) {
  const promises = urls.map(url => 
    limit(() => axiosInstance.get(url))
  );
  
  return Promise.allSettled(promises);
}

4. Xoay vòng User-Agent

Kết hợp xoay vòng proxy với xoay vòng User-Agent để tăng cường tính ẩn danh:

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. Giám sát và ghi lại

Triển khai hệ thống giám sát để theo dõi hiệu suất của proxy:

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(/\/\/.*@/, '//***@'), // Ẩn thông tin xác thực
        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();

// Bọc cho các yêu cầu với giám sát
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;
  }
}

// Xuất báo cáo định kỳ
setInterval(() => {
  console.table(monitor.getReport());
}, 60000);

6. Lựa chọn loại proxy

Chọn loại proxy tùy thuộc vào nhiệm vụ:

Nhiệm vụ Loại đề xuất Lý do
Phân tích hàng loạt dữ liệu công khai Proxy trung tâm dữ liệu Tốc độ cao, giá thấp
Làm việc với mạng xã hội và các nền tảng có bảo vệ Proxy dân cư IP thực, rủi ro bị chặn thấp
Mô phỏng lưu lượng di động Proxy di động IP của nhà mạng di động
Làm việc với các giao thức không chuẩn Proxy SOCKS5 Hỗ trợ bất kỳ lưu lượng nào

Đối với các nhiệm vụ yêu cầu mức độ ẩn danh cao và rủi ro bị chặn tối thiểu, nên sử dụng proxy dân cư. Đối với việc phân tích tốc độ cao với khối lượng lớn dữ liệu, các proxy trung tâm dữ liệu là lựa chọn phù hợp.

7. Bảo mật thông tin xác thực

Không bao giờ lưu trữ thông tin xác thực proxy trong mã. Sử dụng biến môi trường:

// Tệp .env
PROXY_HOST=proxy-server.com
PROXY_PORT=8080
PROXY_USERNAME=your-username
PROXY_PASSWORD=your-password

// Trong mã
require('dotenv').config();

const proxyUrl = `http://${process.env.PROXY_USERNAME}:${process.env.PROXY_PASSWORD}@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;

// Hoặc cho danh sách proxy
const proxyList = process.env.PROXY_LIST.split(',').map(proxy => proxy.trim());

Kết luận

Cài đặt proxy trong các ứng dụng Node.js là một kỹ năng quan trọng cho các nhà phát triển làm việc với phân tích, tự động hóa và tích hợp với các API bên ngoài. Trong hướng dẫn này, chúng ta đã xem xét tất cả các cách cơ bản để làm việc với proxy: từ cài đặt cơ bản qua các mô-đun tích hợp đến các kỹ thuật nâng cao với xoay vòng, xử lý lỗi và giám sát.

Những điểm chính cần nhớ:

  • Chọn thư viện cho các yêu cầu HTTP tùy thuộc vào nhiệm vụ: Axios cho tính linh hoạt, Got cho các dự án TypeScript, node-fetch cho tính tương thích với API trên trình duyệt
  • Sử dụng proxy SOCKS5 cho các giao thức không chuẩn và tính linh hoạt tối đa
  • Triển khai xoay vòng proxy để phân phối tải và tránh bị chặn
  • Triển khai hệ thống xử lý lỗi với các lần thử lại tự động và chuyển đổi proxy
  • Giám sát hiệu suất của proxy và tự động loại trừ các proxy không hoạt động
  • Tái sử dụng các tác nhân HTTP và thiết lập thời gian chờ hợp lý
  • Lưu trữ thông tin xác thực trong biến môi trường, không phải trong mã

Khi chọn proxy cho các ứng dụng Node.js của bạn, hãy xem xét đặc thù của nhiệm vụ. Đối với việc phân tích các nền tảng bảo mật và làm việc với các API nhạy cảm với danh tiếng IP, chúng tôi khuyên bạn nên sử dụng proxy dân cư — chúng cung cấp mức độ ẩn danh cao và rủi ro bị chặn tối thiểu nhờ vào việc sử dụng các địa chỉ IP thực của người dùng gia đình.

```