使用Node实现Http代理

作者:zb日期:2017-02-17 18:04:12 点击:2302

 在前端开发中,我们越来越来不开http代理的使用,例如我们常用fiddle(或chales)的原理就是代理到你本机的域名,当我们跨域GFW到外面呼吸新鲜空气也需要通过代理来实现,当我们需要本地直接映射到线上代码时,http proxy也能帮我们实现。

通常我们所说的代理来源于http1.1的定义,代理扮演的是「中间人」角色,对于连接到它的客户端来说,它是服务端;对于要连接的服务端来说,它是客户端。它就负责在两端之间来回传送 HTTP 报文。

假如我通过代理访问A网站,对于A来说,它会把代理当做客户端,完全察觉不到真正客户端的存在,这实现了隐藏客户端IP的目的。

接下来我们尝试用node来搭建一个本地http代理,然后尝试用第三方插件来实现。

原生版本http proxy

var http = require("http");
var url = require("url");
//首先启动本地服务器
http.createServer(function(req, res) {
//客户端请求有两种方式,可以是对象,也可以是url字符串
//1.这里采取的是对象形式,包括url对象以及headers
var options = url.parse(req.url);
options.headers = req.headers;
//2.如果采取字符串形式,就传入一个完整的url字符串,node会自动解析成url对象

//通过客户端请求新建一个代理服务器
//代理请求仿照本地请求头的数据
var proxyRequest = http.request(options, function(proxyResponse) { //代理请求获取的数据再返回给本地res
proxyResponse.on('data', function(chunk) {
console.log('proxyResponse length:', chunk.length);
res.write(chunk, 'binary');
});
//当代理请求不再收到新的数据,告知本地res数据写入完毕。
proxyResponse.on('end', function() {
console.log('proxied request ended');
res.end();
});

res.writeHead(proxyResponse.statusCode, proxyResponse.headers);
});

//data只有当请求体数据进来时才会触发
//尽管没有请求体数据进来,data还是要写,否则不会触发end事件
req.on('data', function(chunk) {
console.log('in request length:', chunk.length);
proxyRequest.write(chunk, 'binary');
});

req.on('end', function() {
//向proxy发送求情,这里end方法必须被调用才能发起代理请求
//所有的客户端请求都需要通过end来发起
proxyRequest.end();
});

}).listen(8080);

原生实现proxy涉及到很多知识点,初学者一下子很难完全理解,一般我们建议可以通过第三方request客户端请求模块简化代码逻辑:

request版本代理实现

request是基于node实现的客户端请求npm组件,我们来看下如何使用request来实现和原生一样的http代理。

var http = require('http');
var url = require('url');
var request = require('request');

var server = http.createServer(onRequest).listen(3000);

function onRequest(req, res) {
req.url = (req.connection.encrypted ? 'https': 'http') + '://' + req.headers.host + req.url;
var queryData = url.parse(req.url, true).query;
if (queryData.url) {
//request方法返回的对象兼具可读和可写权限,所以可以直接通过pipe给客户端返回值
request({
url: queryData.url
}).on('error', function(e) {
res.end(e);
}).pipe(res);
}
else {
res.end("no url found");
}
}

request版本的http代理比起原生node版已经前进了一大步,不过我们的目标是有第三方npm包能够直接模块式引入,这样在我们的业务代码里面直接require即可,还好,开源社区为我们提供proxy-middleware这个npm包,接下来我们直接来实现proxy-middleware版本的http代理。

proxy-middleware版本代理实现

proxy-middleware组件包可以让我们在项目里面直接模块式引入,仅需配置选项就能实现http代理,推荐使用。 
我么来写个简单的demo来验证下:

var express = require('express');
var url = require('url');
var proxy = require('proxy-middleware');
var fs = require('fs');

var app = express();
var port = 9999;

//代理地址url对象,必选
var proxyOptions = url.parse('http://8.wacai.com');

//这里配置代理选项,只有匹配到route父规则的链接才能触发代理,注意链接可以完全一样,也可以后面加上?foo=bar,也可以加上/sunLink等等。
proxyOptions.route = '/';

//完全匹配
app.use('/', proxy(proxyOptions));
//这样能匹配
app.use('/aaa/bbb', proxy(proxyOptions));
//这样也能匹配
app.use('/aaa/bbb?foo=bar', proxy(proxyOptions));

app.get("/finance/common/index_tab.action",function(req,res){
res.end("123");
})

app.listen(port, function () {
console.log('mock server starting on port ' + port);
});

总结

我们分别用node原生、node配合request组件,第三方模块三种方式实现node的http代理机制,分别适合不同场景下使用。

上一篇: WebPack基础入门教程

下一篇: React从入门到精通系列之(5)state管理和生命周期钩子