内容简介:我们上线一个网站,往往需要代理来完成需求,不然的话就只能使用最简单的做法是拿已经写好的包直接使用上面: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版本
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Developer's Guide to Social Programming
Mark D. Hawker / Addison-Wesley Professional / 2010-8-25 / USD 39.99
In The Developer's Guide to Social Programming, Mark Hawker shows developers how to build applications that integrate with the major social networking sites. Unlike competitive books that focus on a s......一起来看看 《Developer's Guide to Social Programming》 这本书的介绍吧!