بازگشت به وبلاگ

تنظیم پروکسی در برنامه‌های Node.js: راهنمای کامل با مثال‌های کد

راهنمای جامع برای ادغام پروکسی در Node.js: از تنظیمات پایه تا تکنیک‌های پیشرفته چرخش IP و مدیریت خطاها.

📅۲۵ بهمن ۱۴۰۴
```html

هنگام توسعه برنامه‌های Node.js برای پارس کردن، اتوماسیون یا کار با API، اغلب نیاز به استفاده از سرورهای پروکسی وجود دارد. این امکان را فراهم می‌کند که محدودیت‌های جغرافیایی را دور بزنید، بار را توزیع کنید و از مسدود شدن بر اساس IP جلوگیری کنید. در این راهنما تمام روش‌های تنظیم پروکسی در Node.js را بررسی خواهیم کرد — از روش‌های پایه تا تکنیک‌های پیشرفته با چرخش و مدیریت خطاها.

مفاهیم پایه کار با پروکسی در Node.js

سرور پروکسی در Node.js به عنوان واسطه‌ای بین برنامه شما و سرور هدف عمل می‌کند. زمانی که شما یک درخواست HTTP را از طریق پروکسی ارسال می‌کنید، برنامه شما ابتدا به سرور پروکسی متصل می‌شود که سپس درخواست را به آدرس نهایی هدایت می‌کند. این امکان را فراهم می‌کند که آدرس IP واقعی سرور شما پنهان شود و از آدرس IP پروکسی استفاده شود.

در Node.js چندین روش اصلی برای کار با پروکسی وجود دارد که به کتابخانه‌ای که برای درخواست‌های HTTP استفاده می‌شود بستگی دارد. گزینه‌های محبوب‌تر عبارتند از:

  • ماژول‌های داخلی http/https — عملکرد پایه بدون وابستگی‌های اضافی
  • Axios — کتابخانه‌ای محبوب با API کاربرپسند و پشتیبانی از پرومیس‌ها
  • Got — جایگزینی مدرن با پشتیبانی از TypeScript
  • node-fetch — پیاده‌سازی Fetch API برای Node.js
  • request — کتابخانه‌ای قدیمی که هنوز هم استفاده می‌شود (برای پروژه‌های جدید توصیه نمی‌شود)

سرورهای پروکسی از پروتکل‌های مختلفی پشتیبانی می‌کنند. برای کار با Node.js، بیشتر از پروتکل‌های زیر استفاده می‌شود:

پروتکل توضیحات کاربرد
HTTP پروتکل پایه برای اتصالات غیر رمزگذاری شده پارس کردن، کار با API بدون SSL
HTTPS پروکسی با پشتیبانی از رمزگذاری SSL/TLS اتصالات امن، کار با API‌های محافظت شده
SOCKS5 پروتکل جهانی برای هر نوع ترافیک WebSocket، UDP، سناریوهای پیچیده

برای وظایف پارس کردن و اتوماسیون، توسعه‌دهندگان اغلب از پروکسی‌های مسکونی استفاده می‌کنند، زیرا آن‌ها دارای آدرس‌های IP واقعی کاربران خانگی هستند و کمتر تحت مسدودیت‌های سایت‌های هدف قرار می‌گیرند.

تنظیم پروکسی از طریق ماژول داخلی http/https

Node.js ماژول‌های داخلی http و https را برای کار با درخواست‌های HTTP ارائه می‌دهد. برای اتصال پروکسی می‌توان از کتابخانه 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 — یکی از محبوب‌ترین کتابخانه‌ها برای درخواست‌های HTTP در Node.js است. این کتابخانه 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();

برای کار با پروکسی HTTPS از طریق روش CONNECT می‌توانید از عوامل اضافی استفاده کنید:

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 پیاده‌سازی استاندارد Fetch API برای Node.js است.

کار با پروکسی در 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 مرورگر آشنا هستند مناسب است.

اتصال پروکسی SOCKS5 از طریق socks-proxy-agent

SOCKS5 — پروتکل جهانی پروکسی است که در سطح پایین‌تری از HTTP/HTTPS کار می‌کند. این پروتکل از هر نوع ترافیکی پشتیبانی می‌کند، از جمله UDP و اتصالات WebSocket. برای کار با SOCKS5 در Node.js از کتابخانه 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);
});

استفاده از SOCKS5 با 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('داده‌ها از طریق SOCKS5:', response.data);
    return response.data;
  } catch (error) {
    console.error('خطای درخواست SOCKS5:', error.message);
    throw error;
  }
}

fetchViaSocks5();

پروکسی‌های SOCKS5 به ویژه برای وظایفی که نیاز به کار با پروتکل‌های غیر استاندارد دارند یا زمانی که نیاز به حداکثر انعطاف‌پذیری است، مفید هستند. بسیاری از ارائه‌دهندگان پروکسی‌های موبایل با پشتیبانی از SOCKS5 را ارائه می‌دهند که امکان شبیه‌سازی ترافیک موبایل برای کار با API‌های موبایل را فراهم می‌کند.

پیاده‌سازی چرخش پروکسی برای توزیع بار

هنگام پارس کردن حجم‌های بزرگ داده یا کار با API‌هایی که محدودیت‌هایی برای تعداد درخواست‌ها از یک IP دارند، باید از چرخش پروکسی استفاده کنید. این امکان را فراهم می‌کند که درخواست‌ها بین چندین سرور پروکسی توزیع شوند و از مسدود شدن جلوگیری شود.

مثال پیاده‌سازی چرخش پروکسی ساده:

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(`حداکثر تعداد تکرارها (${this.maxRetries}) برای ${url} رسید`);
        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 handshake
  //   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 خود، به ویژگی‌های وظیفه توجه کنید. برای پارس کردن پلتفرم‌های محافظت شده و کار با API‌هایی که به شهرت IP حساس هستند، توصیه می‌شود از پروکسی‌های مسکونی استفاده کنید — آن‌ها سطح بالایی از ناشناسی و حداقل ریسک مسدود شدن را با استفاده از آدرس‌های IP واقعی کاربران خانگی فراهم می‌کنند.

```