内容简介:我们上线一个网站,往往需要代理来完成需求,不然的话就只能使用最简单的做法是拿已经写好的包直接使用上面:point_up_2:代码监听
我们上线一个网站,往往需要代理来完成需求,不然的话就只能使用 IP
加端口的方式来访问应用,目前基本上都会使用 Nginx
来完成反向代理,那么我们开发 Node
应用一定需要 Nginx
吗?肯定不是,我们完全可以通过 Node
来做,但是大多是不建议你用 Node
去处理,因为 Nginx
功能更强大,比如负载均衡,本文主要是帮你了解如何通过 Node
实现代理
使用http-proxy
最简单的做法是拿已经写好的包直接使用
$ cnpm i http-proxy
const proxy = require("http-proxy").createProxyServer({});
server = require("http").createServer(function(req, res) {
const host = req.headers.host;
switch (host) {
case "your domain":
proxy.web(req, res, { target: "http://localhost:8000" });
break;
default:
res.writeHead(200, {
"Content-Type": "text/plain"
});
res.end("Welcome to my server!");
}
});
console.log("listening on port 80");
server.listen(80);
上面:point_up_2:代码监听 80
端口(如果你的服务器目前使用来 Nginx
,暂用 80
端口的话,需要先暂停 Nginx
服务),然后我们通过访问域名(前提是域名做好了解析),然后使用 proxy.web
方法反向代理到当前服务下的 8000
端口,到此一个简单的服务完成了
原生实现
const http = require("http");
const url = require("url");
function request(req, res) {
const reqUrl = url.parse(req.url);
const target = url.parse("http://localhost:3000");
const options = {
hostname: target.hostname,
port: target.port,
path: reqUrl.path,
method: req.method,
headers: req.headers
};
const proxyReq = http.request(options);
proxyReq.on("response", proxyRes => {
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
});
req.pipe(proxyReq);
}
http
.createServer()
.on("request", request)
.listen(8003);
是不是很简单?通过访问 8003
端口,我们将请求转发到 3000
端口,可以复制当前代码尝试一下,前提是 3000
端口可以正常访问。当访问 8003
端口的时候,内部重新请求我们需要代理的地址,然后通过 pipe
返回转发后的数据
http-proxy源码实现原理
执行 proxy.web
function ProxyServer(options) {
...
this.web = this.proxyRequest = createRightProxy('web')(options);
...
}
内部关键代码执行了一下这段, passes
是一个数组方法,包含 deleteLength
、 timeout
、 XHeaders
、 stream
,关键点在 stream
,其他基本是辅助作用, XHeaders
功能是设置 x-forwarded-*
这种 header
,不过前提是 option
配置了 xfwd
才行, timeout
是设置超时时间的, deleteLength
只有请求方法是 OPTIONS
和 DELETE
才会执行
...
for(var i=0; i < passes.length; i++) {
if(passes[i](req, res, requestOptions, head, this, cbl)) { // passes can return a truthy value to halt the loop
break;
}
}
stream
方法
module.exports = {
deleteLength: ....,
timeout: ...,
XHeaders: ...,
stream: function stream(req, res, options, _, server, clb) {
// And we begin!
server.emit('start', req, res, options.target || options.forward);
var agents = options.followRedirects ? followRedirects : nativeAgents;
var http = agents.http;
var https = agents.https;
if(options.forward) {
// If forward enable, so just pipe the request
var forwardReq = (options.forward.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req, 'forward')
);
// error handler (e.g. ECONNRESET, ECONNREFUSED)
// Handle errors on incoming request as well as it makes sense to
var forwardError = createErrorHandler(forwardReq, options.forward);
req.on('error', forwardError);
forwardReq.on('error', forwardError);
(options.buffer || req).pipe(forwardReq);
if(!options.target) { return res.end(); }
}
// Request initalization
var proxyReq = (options.target.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req)
);
// Enable developers to modify the proxyReq before headers are sent
proxyReq.on('socket', function(socket) {
if(server) { server.emit('proxyReq', proxyReq, req, res, options); }
});
// allow outgoing socket to timeout so that we could
// show an error page at the initial request
if(options.proxyTimeout) {
proxyReq.setTimeout(options.proxyTimeout, function() {
proxyReq.abort();
});
}
// Ensure we abort proxy if request is aborted
req.on('aborted', function () {
proxyReq.abort();
});
// handle errors in proxy and incoming request, just like for forward proxy
var proxyError = createErrorHandler(proxyReq, options.target);
req.on('error', proxyError);
proxyReq.on('error', proxyError);
function createErrorHandler(proxyReq, url) {
return function proxyError(err) {
if (req.socket.destroyed && err.code === 'ECONNRESET') {
server.emit('econnreset', err, req, res, url);
return proxyReq.abort();
}
if (clb) {
clb(err, req, res, url);
} else {
server.emit('error', err, req, res, url);
}
}
}
(options.buffer || req).pipe(proxyReq);
proxyReq.on('response', function(proxyRes) {
if(server) { server.emit('proxyRes', proxyRes, req, res); }
if(!res.headersSent && !options.selfHandleResponse) {
for(var i=0; i < web_o.length; i++) {
if(web_o[i](req, res, proxyRes, options)) { break; }
}
}
if (!res.finished) {
// Allow us to listen when the proxy has completed
proxyRes.on('end', function () {
if (server) server.emit('end', req, res, proxyRes);
});
// We pipe to the response unless its expected to be handled by the user
if (!options.selfHandleResponse) proxyRes.pipe(res);
} else {
if (server) server.emit('end', req, res, proxyRes);
}
});
}
}
关键代码
// Request initalization
var proxyReq = (options.target.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req)
);
(options.buffer || req).pipe(proxyReq);
proxyReq.on('response', function(proxyRes) {
if(!res.headersSent && !options.selfHandleResponse) {
for(var i=0; i < web_o.length; i++) {
if(web_o[i](req, res, proxyRes, options)) { break; }
}
}
if (!res.finished) {
// We pipe to the response unless its expected to be handled by the user
if (!options.selfHandleResponse) proxyRes.pipe(res);
}
});
实现大致和我们之前写得差不多,但是他考虑得更多,支持 https
,错误处理也做得很好,已经很成熟了
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 动态代理三部曲(一):动态代理模式及实现原理
- 使用 Javassist 实现动态代理
- Javassist实现JDK动态代理
- 代理模式-go/java实现
- 中通安全访问代理设计与实现
- vue配置文件实现代理v2版本
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Paradigms of Artificial Intelligence Programming
Peter Norvig / Morgan Kaufmann / 1991-10-01 / USD 77.95
Paradigms of AI Programming is the first text to teach advanced Common Lisp techniques in the context of building major AI systems. By reconstructing authentic, complex AI programs using state-of-the-......一起来看看 《Paradigms of Artificial Intelligence Programming》 这本书的介绍吧!