如何手动实现nodejs代理服务器

发布时间:2021-07-15 15:40:49 作者:chen
来源:亿速云 阅读:175
# 如何手动实现Node.js代理服务器

## 目录
1. [代理服务器基础概念](#一代理服务器基础概念)
   - 1.1 [什么是代理服务器](#11-什么是代理服务器)
   - 1.2 [代理类型分类](#12-代理类型分类)
   - 1.3 [常见应用场景](#13-常见应用场景)
2. [Node.js核心模块准备](#二nodejs核心模块准备)
   - 2.1 [HTTP/HTTPS模块](#21-httphttps模块)
   - 2.2 [Net模块与流处理](#22-net模块与流处理)
   - 2.3 [EventEmitter事件机制](#23-eventemitter事件机制)
3. [基础代理实现](#三基础代理实现)
   - 3.1 [HTTP正向代理实现](#31-http正向代理实现)
   - 3.2 [HTTPS请求处理](#32-https请求处理)
   - 3.3 [请求头关键字段处理](#33-请求头关键字段处理)
4. [高级功能扩展](#四高级功能扩展)
   - 4.1 [连接池优化](#41-连接池优化)
   - 4.2 [缓存机制实现](#42-缓存机制实现)
   - 4.3 [负载均衡策略](#43-负载均衡策略)
5. [安全防护措施](#五安全防护措施)
   - 5.1 [请求过滤](#51-请求过滤)
   - 5.2 [流量加密](#52-流量加密)
   - 5.3 [DDoS防护](#53-ddos防护)
6. [性能监控与调优](#六性能监控与调优)
   - 6.1 [关键指标监控](#61-关键指标监控)
   - 6.2 [内存泄漏排查](#62-内存泄漏排查)
   - 6.3 [压力测试方法](#63-压力测试方法)
7. [完整代码实现](#七完整代码实现)
8. [部署与运维](#八部署与运维)

## 一、代理服务器基础概念

### 1.1 什么是代理服务器

代理服务器(Proxy Server)作为网络信息的中转站,主要功能包括:
- **中介角色**:在客户端和目标服务器之间建立间接连接
- **请求转发**:解析客户端请求并转发到目标服务器
- **响应回传**:将服务器响应按原路径返回客户端

典型工作流程:
```mermaid
sequenceDiagram
    Client->>Proxy: 发送请求
    Proxy->>Target: 转发请求
    Target->>Proxy: 返回响应
    Proxy->>Client: 回传响应

1.2 代理类型分类

分类维度 类型 特点描述
网络层级 应用层代理 处理HTTP/HTTPS等高层协议
传输层代理 处理TCP/UDP原始数据流
流量方向 正向代理 代表客户端访问外部资源
反向代理 代表服务器接收客户端请求
协议支持 HTTP代理 处理Web流量
SOCKS代理 通用套接字代理

1.3 常见应用场景

  1. 企业网络管理

    • 员工上网行为监控
    • 内容过滤(屏蔽危险网站)
    • 带宽流量控制
  2. 开发调试工具

    • 抓包分析(如Fiddler、Charles)
    • API请求拦截和修改
    • 移动端真机调试
  3. 性能优化

    • 缓存静态资源
    • 压缩传输数据
    • 减少源服务器负载

二、Node.js核心模块准备

2.1 HTTP/HTTPS模块

创建基础HTTP服务器模板:

const http = require('http');

const server = http.createServer((clientReq, clientRes) => {
  // 请求处理逻辑
  console.log(`接收到请求: ${clientReq.method} ${clientReq.url}`);
});

server.listen(8080, () => {
  console.log('代理服务器运行在 http://localhost:8080');
});

HTTPS服务器关键配置:

const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem')
};

https.createServer(options, (req, res) => {
  // HTTPS处理逻辑
}).listen(443);

2.2 Net模块与流处理

TCP代理核心代码段:

const net = require('net');

const proxy = net.createServer((clientSocket) => {
  const serverSocket = net.connect({
    host: 'target-host',
    port: 80
  });
  
  // 双向管道连接
  clientSocket.pipe(serverSocket);
  serverSocket.pipe(clientSocket);
  
  // 错误处理
  clientSocket.on('error', (err) => {
    console.error('客户端连接错误:', err);
  });
});

proxy.listen(8888);

2.3 EventEmitter事件机制

自定义代理事件处理:

const EventEmitter = require('events');

class ProxyEmitter extends EventEmitter {
  constructor() {
    super();
    this.requestCount = 0;
  }
}

const emitter = new ProxyEmitter();

emitter.on('request', (url) => {
  console.log(`处理请求: ${url}`);
  emitter.requestCount++;
});

// 触发自定义事件
setInterval(() => {
  emitter.emit('request', 'http://example.com/api');
}, 1000);

三、基础代理实现

3.1 HTTP正向代理实现

完整代理示例:

const http = require('http');

http.createServer((clientReq, clientRes) => {
  // 解析目标URL
  const options = {
    hostname: clientReq.headers.host,
    port: 80,
    path: clientReq.url,
    method: clientReq.method,
    headers: clientReq.headers
  };

  // 创建代理请求
  const proxyReq = http.request(options, (proxyRes) => {
    clientRes.writeHead(proxyRes.statusCode, proxyRes.headers);
    proxyRes.pipe(clientRes);
  });

  clientReq.pipe(proxyReq);
  
  proxyReq.on('error', (e) => {
    console.error(`代理请求错误: ${e.message}`);
    clientRes.end();
  });
}).listen(8080);

3.2 HTTPS请求处理

CONNECT方法实现:

const net = require('net');
const http = require('http');

http.createServer((clientReq, clientRes) => {
  if (clientReq.method === 'CONNECT') {
    const [host, port] = clientReq.url.split(':');
    
    const serverSocket = net.connect(port || 443, host, () => {
      clientRes.write('HTTP/1.1 200 Connection Established\r\n\r\n');
      clientReq.socket.pipe(serverSocket);
      serverSocket.pipe(clientReq.socket);
    });
    
    serverSocket.on('error', (e) => {
      console.error(`HTTPS连接错误: ${e}`);
      clientReq.socket.end();
    });
  } else {
    // 处理普通HTTP请求
  }
}).listen(8888);

3.3 请求头关键字段处理

必须修改的请求头字段:

function processHeaders(originalHeaders) {
  const headers = { ...originalHeaders };
  
  // 删除可能引起问题的头字段
  delete headers['proxy-connection'];
  delete headers['connection'];
  delete headers['keep-alive'];
  
  // 添加必要字段
  headers['connection'] = 'close';
  headers['x-forwarded-for'] = originalHeaders['x-forwarded-for'] || 
    clientReq.connection.remoteAddress;
  
  return headers;
}

四、高级功能扩展

4.1 连接池优化

使用generic-pool实现:

const genericPool = require('generic-pool');

const factory = {
  create: () => net.createConnection(80, 'target-host'),
  destroy: (socket) => socket.end()
};

const pool = genericPool.createPool(factory, {
  max: 10,
  min: 2
});

// 使用连接池
pool.acquire().then((socket) => {
  clientReq.pipe(socket);
  socket.pipe(clientRes);
  pool.release(socket);
});

4.2 缓存机制实现

内存缓存示例:

const cache = new Map();

function checkCache(req) {
  const key = `${req.method}:${req.url}`;
  if (cache.has(key)) {
    const { data, expire } = cache.get(key);
    if (Date.now() < expire) {
      return data;
    }
    cache.delete(key);
  }
  return null;
}

function setCache(req, data, ttl = 60000) {
  const key = `${req.method}:${req.url}`;
  cache.set(key, {
    data,
    expire: Date.now() + ttl
  });
}

4.3 负载均衡策略

轮询算法实现:

const servers = [
  { host: 'server1.example.com', port: 80 },
  { host: 'server2.example.com', port: 80 }
];

let currentIndex = 0;

function getNextServer() {
  const server = servers[currentIndex];
  currentIndex = (currentIndex + 1) % servers.length;
  return server;
}

五、安全防护措施

5.1 请求过滤

黑名单实现:

const blacklist = ['/admin', '/wp-login.php'];

function isRequestAllowed(url) {
  return !blacklist.some(path => url.includes(path));
}

// 在请求处理中调用
if (!isRequestAllowed(clientReq.url)) {
  clientRes.writeHead(403);
  return clientRes.end('Forbidden');
}

5.2 流量加密

TLS配置示例:

const tls = require('tls');
const fs = require('fs');

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt'),
  minVersion: 'TLSv1.2',
  ciphers: 'ECDHE-ECDSA-AES256-GCM-SHA384:HIGH:!aNULL:!MD5'
};

tls.createServer(options, (socket) => {
  // 处理加密连接
}).listen(443);

5.3 DDoS防护

限流中间件:

const rateLimit = new Map();

function checkRateLimit(ip) {
  const now = Date.now();
  const windowStart = now - 60000; // 1分钟窗口
  
  // 清理旧记录
  rateLimit.forEach((timestamps, key) => {
    const filtered = timestamps.filter(t => t > windowStart);
    if (filtered.length > 0) {
      rateLimit.set(key, filtered);
    } else {
      rateLimit.delete(key);
    }
  });
  
  // 添加新记录
  if (!rateLimit.has(ip)) {
    rateLimit.set(ip, [now]);
    return true;
  }
  
  const timestamps = rateLimit.get(ip);
  timestamps.push(now);
  
  // 超过100次/分钟则拒绝
  return timestamps.length <= 100;
}

六、性能监控与调优

6.1 关键指标监控

监控指标示例:

const stats = {
  totalRequests: 0,
  activeConnections: 0,
  requestTimings: [],
  errorCount: 0
};

// 在请求处理中更新
clientReq.on('end', () => {
  stats.totalRequests++;
  stats.activeConnections--;
});

// 定时输出报告
setInterval(() => {
  console.log(`
    请求统计:
    - 总请求量: ${stats.totalRequests}
    - 活跃连接: ${stats.activeConnections}
    - 错误率: ${(stats.errorCount / stats.totalRequests * 100).toFixed(2)}%
    - 平均响应时间: ${calculateAverage(stats.requestTimings)}ms
  `);
}, 60000);

6.2 内存泄漏排查

使用heapdump:

const heapdump = require('heapdump');

// 内存超过500MB时生成堆快照
setInterval(() => {
  const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024;
  if (memoryUsage > 500) {
    const filename = `heapdump-${Date.now()}.heapsnapshot`;
    heapdump.writeSnapshot(filename);
    console.warn(`内存过高: ${memoryUsage.toFixed(2)}MB,已生成快照 ${filename}`);
  }
}, 30000);

6.3 压力测试方法

使用autocannon测试:

npm install -g autocannon
autocannon -c 100 -d 60 http://localhost:8080

测试结果分析指标: - 请求吞吐量(Requests/second) - 延迟分布(Latency percentile) - 错误率(Error rate) - 吞吐量(Throughput)

七、完整代码实现

综合所有功能的完整代理:

const http = require('http');
const net = require('net');
const url = require('url');

class ProxyServer {
  constructor(options = {}) {
    this.port = options.port || 8080;
    this.cache = new Map();
    this.stats = {
      requests: 0,
      connections: 0
    };
  }

  start() {
    this.server = http.createServer(this.handleRequest.bind(this))
      .listen(this.port, () => {
        console.log(`Proxy server running on port ${this.port}`);
      });
    
    // HTTPS隧道支持
    this.server.on('connect', this.handleConnect.bind(this));
  }

  async handleRequest(clientReq, clientRes) {
    this.stats.requests++;
    this.stats.connections++;
    
    try {
      const targetUrl = url.parse(clientReq.url);
      const options = {
        hostname: targetUrl.hostname || clientReq.headers.host,
        port: targetUrl.port || 80,
        path: targetUrl.path,
        method: clientReq.method,
        headers: this.processHeaders(clientReq.headers)
      };
      
      // 缓存检查
      const cacheKey = `${options.method}:${options.hostname}${options.path}`;
      if (this.cache.has(cacheKey)) {
        const { data, expires } = this.cache.get(cacheKey);
        if (Date.now() < expires) {
          clientRes.writeHead(200, { 'Content-Type': 'text/html' });
          return clientRes.end(data);
        }
        this.cache.delete(cacheKey);
      }
      
      // 转发请求
      const proxyReq = http.request(options, (proxyRes) => {
        // 缓存响应
        if (proxyRes.statusCode === 200 && options.method === 'GET') {
          let body = '';
          proxyRes.on('data', (chunk) => body += chunk);
          proxyRes.on('end', () => {
            this.cache.set(cacheKey, {
              data: body,
              expires: Date.now() + 60000
            });
          });
        }
        
        clientRes.writeHead(proxyRes.statusCode, proxyRes.headers);
        proxyRes.pipe(clientRes);
      });
      
      clientReq.pipe(proxyReq);
      proxyReq.on('error', (err) => this.handleError(err, clientRes));
    } catch (err) {
      this.handleError(err, clientRes);
    } finally {
      clientRes.on('finish', () => {
        this.stats.connections--;
      });
    }
  }

  handleConnect(clientReq, clientSocket) {
    const [hostname, port] = clientReq.url.split(':');
    const targetSocket = net.connect(port || 443, hostname, () => {
      clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
      targetSocket.pipe(clientSocket);
      clientSocket.pipe(targetSocket);
    });
    
    targetSocket.on('error', (err) => {
      console.error('HTTPS隧道错误:', err);
      clientSocket.end();
    });
  }

  processHeaders(headers) {
    const filtered = { ...headers };
    delete filtered['proxy-connection'];
    filtered['connection'] = 'close';
    filtered['x-forwarded-for'] = headers['x-forwarded-for'] || 'unknown';
    return filtered;
  }

  handleError(err, response) {
    console.error('代理错误:', err);
    if (!response.headersSent) {
      response.writeHead(500);
    }
    response.end(`Proxy Error: ${err.message}`);
  }
}

// 启动代理
const proxy = new ProxyServer({ port: 8080 });
proxy.start();

八、部署与运维

生产环境部署建议

  1. 进程管理

    • 使用PM2进行进程守护
    pm2 start proxy.js -i max --name "proxy-server"
    
  2. 日志记录

    • 配置Morgan日志中间件

    ”`javascript const fs = require(‘fs’); const morgan = require(‘morgan’);

const accessLogStream = fs.createWriteStream(‘/var/log/proxy-access.log’); app.use(morgan(‘combined’, { stream: accessLogStream }));


3. **性能调优**
   - 调整Node.js事件循环参数
   ```bash
   NODE_OPTIONS="--max-old-space-size=4096" pm2 restart proxy-server
  1. 安全加固
    • 定期更新依赖项
    npm audit fix --force
    
    • 配置防火墙规则
    iptables -A INPUT -p tcp --dport 8080 -j DROP
    iptables -I INPUT -p tcp --dport 8080 -s 192.168.1.0/24 -j ACCEPT
    

监控方案推荐

  1. Prometheus + Grafana

    • 监控指标:
      • 请求吞吐量
      • 平均响应时间
      • 内存使用情况
      • 活跃连接数
  2. ELK日志分析

    • 日志收集架构:
    Filebeat -> Logstash -> Elasticsearch -> Kibana
    
  3. **健康

推荐阅读:
  1. Nodejs怎么实现WebSocket
  2. NodeJS怎么实现同步

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

nodejs 代理服务器

上一篇:ASP.NET中RenderContents如何使用

下一篇:ASP.NET中怎么捕获回传事件

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》