100行代码实现一个多功能的代理服务

本文通过100行代码详细介绍了如何在NodeJS中实现HTTP普通代理、HTTP隧道代理和TCP代理。文章首先解释了代理服务的工作原理,然后分别展示了20行左右的代码来实现每种代理。HTTP普通代理通过解析URL获取目标服务器地址,建立并转发HTTP请求。HTTP隧道代理利用HTTP CONNECT方法建立TCP连接,处理HTTPS的证书验证和隐私保护。TCP代理则直接在TCP层面建立连接。最后,文章讨论了多功能代理服务的实现,并给出了代码中使用HTTP代理的方法。
摘要由CSDN通过智能技术生成

TL;DR: 上一篇文章我们介绍了关于计算机网络代理的定义,代理的类型 以及其对应的实现原理。这篇文章将通过手写代码的方式,用100行代码实现一个同时支持HTTP普通代理,隧道代理,以及TCP代理的代理软件。同时介绍中业务代码如何使用HTTP代理。

实现HTTP普通代理

《HTTP权威指南》图描述了普通代理的基本原理:
在这里插入图片描述

看样子我们在中间实现一个API服务,满足左手交右手的功能即可。那中间的这个API服务要怎么知道你最终要去的目标服务器是哪里呢?所以这里在客户端跟代理服务器之间要有一个约定,客户端要把目标地址放到url里面,当代理服务器收到请求时,从url解析出目标服务器的地址,再向目标服务器发起请求,把返回的内容再发送给客户端,整个过程就完成了。

下面的20行左右的代码就可以在NodeJS里面实现了这个 普通代理。

function request(srcReq, srcRes) {
   
    const url = new URL(srcReq.url);
    const options = {
   
        hostname: url.hostname,
        port: url.port || 80,
        path: url.pathname,
        method: srcReq.method,
        headers: srcReq.headers
    }
    // timestamp clientAddress requestMethod URI result/statusCodes responseTime
    const startAt = process.hrtime();
    let logLine = `${
     Date.now()} ${
     requestIP.getClientIp(srcReq)} ${
     srcReq.method} ${
     srcReq.url}`
    const destRequest = http.request(options, destResponse => {
   
        srcRes.writeHead(destResponse.statusCode, destResponse.headers);
        destResponse.pipe(srcRes)
        logLine += ` ${
     destResponse.statusCode} ${
     _.get(destResponse.headers,"content-type",'-')} ${
     _getTotalTime(startAt)}`
        access.log(logLine);
    }).on('error', e => {
   
        srcRes.end();
        logLine += ` ERROR ${
     _getTotalTime(startAt)}`;
        error.log(logLine + '\r\n' + e)
    })
    srcReq.pipe(destRequest);
}

http.createServer().on('request', request)

代码的详细介绍如下:

  1. 代理服务收到请求后,从url解析出目标服务器的地址,同时将客户端请求的 path, method 以及 headers都搬过去 ,代码 2-9行
  2. 代理服务向目标服务器发起一个另一个HTTP请求,代码 13-22 行
  3. 把客户端请求的内容,用管道的方式 发送给目标服务器,代码23行
  4. 把目标服务器返回的内容,同样用管道的方式 发送回给客户端,代码15行
  5. 通过Nodejs的 http模块,创建一个服务器。从这里也可以看出来,这个代理服务器是在HTTP 层上面的

实现HTTP隧道代理

关于HTTP普通代理的问题可以参考上一篇文章。HTTP 隧道代理的工作原理如下图:

在这里插入图片描述

通过HTTP CONNECT方法,做客户端跟代理中间建立起一个隧道,然后代理服务器跟目标服务器发起一个SSL的TCP连接,最后代理将与目标服务器建立TCP连接,与客户端之间建立的TCP连接对接起来,从而实现了这个隧道代理的过程。

下面这另外的20行代码也实现了这一过程:

function connect(srcReq, srcSocket) {
   
    const url = new URL(`http://${
     srcReq.url}`);
    const startAt = process.hrtime();
    let logLine = `${
     Date.now()} CONNECT ${
     url.hostname}:${
     url.port}`
    const destSocket = net.connect(parseInt(url.port), url.hostname, () => {
   
        srcSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
        destSocket.pipe(srcSocket);
        logLine += ` ${
     _getTotalTime(startAt)}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值