内容简介:本来源代码版本之前我有一篇很多时候导致这种的原因就是不了解我们使用的东西的本质.
本来源代码版本
- http-proxy: 1.17.0
- http-proxy-middleware 0.19.0
之前我有一篇 Koa下http代理 , 主要是说在开发的时候遇到的一个坑和排查过程. 很多时间结果很简单, 过程却是异常的痛苦.
很多时候导致这种的原因就是不了解我们使用的东西的本质.
所以这一篇就是简单的分析nodejs下的http代理, 当然不会太深入, 因为能力不足.
在express下大家最熟悉的是 http-proxy-middleware
http-proxy-middleware其是基于 http-proxy 封装的.
http-proxy 本身又是基于 http 和 https 封装的
HTTPS 是 HTTP 基于 TLS/SSL 的版本
http里面有个方法叫 http.request , http-proxy主要就是基于这个实现的代理.
http与net模块还有一定关系, net核心方法和类关系如下
net.Server:这个类用于创建 TCP 或 IPC server
net.Socket: 使用它来与server或者客户端通信
举个例子,它是通过net.createConnection()返回的,所以用户可以使用它来与server通信。
当一个连接被接收时,它也能被Node.js创建并传递给用户。比如,它是通过监听在一个net.Server上的’connection’事件触发而获得的,那么用户可以使用它来与客户端通信。
回归正轨
http-proxy-middleware
http-proxy-middleware lib文件下index.js文件
var proxy = httpProxy.createProxyServer({}) logger.info('[HPM] Proxy created:', config.context, ' -> ', proxyOptions.target) var pathRewriter = PathRewriter.create(proxyOptions.pathRewrite) // returns undefined when "pathRewrite" is not provided // attach handler to http-proxy events handlers.init(proxy, proxyOptions) // log errors for debug purpose proxy.on('error', logError) // https://github.com/chimurai/http-proxy-middleware/issues/19 // expose function to upgrade externally middleware.upgrade = wsUpgradeDebounced return middleware function middleware(req, res, next) { if (shouldProxy(config.context, req)) { var activeProxyOptions = prepareProxyRequest(req) proxy.web(req, res, activeProxyOptions) } else { next() } if (proxyOptions.ws === true) { // use initial request to access the server object to subscribe to http upgrade event catchUpgradeRequest(req.connection.server) } }
httpProxy就是http-proxy, 上面大致就是创建了一个proxy, 各种预处理.
最后返回一个中间件.
中间件, 就是检查需不需要代理, 需要的话就进行代理.
proxy.web(req, res, activeProxyOptions)这句就是进行请求, 然后被代理
http-proxy
createProxyServer方法就是http-proxy下面的ProxyServer方法,
ProxyServer是继承eventemitter3的
function ProxyServer(options) { EE3.call(this); options = options || {}; options.prependPath = options.prependPath === false ? false : true; this.web = this.proxyRequest = createRightProxy('web')(options); this.ws = this.proxyWebsocketRequest = createRightProxy('ws')(options); this.options = options; this.webPasses = Object.keys(web).map(function (pass) { return web[pass]; }); this.wsPasses = Object.keys(ws).map(function (pass) { return ws[pass]; }); this.on('error', this.onError, this); }
我们看到了this.web, 我们再追溯createRightProxy, 三层嵌套的函数,执行两次后, 返回的就是function(req, res,…)格式的方法, 刚好对应到http-proxy-middleware 里面的proxy.web的参数.
注意passes这个值,http的话对应上面代码的11行, 是 web = require(‘./passes/web-incoming’)
function createRightProxy(type) { return function (options) { return function (req, res /*, [head], [opts] */) { var passes = (type === 'ws') ? this.wsPasses : this.webPasses, args = [].slice.call(arguments), cntr = args.length - 1, head, cbl; /* optional args parse begin */ if (typeof args[cntr] === 'function') { cbl = args[cntr]; cntr--; } var requestOptions = options; if ( !(args[cntr] instanceof Buffer) && args[cntr] !== res ) { //Copy global options requestOptions = extend({}, options); //Overwrite with request options extend(requestOptions, args[cntr]); cntr--; } if (args[cntr] instanceof Buffer) { head = args[cntr]; } /* optional args parse end */ ['target', 'forward'].forEach(function (e) { if (typeof requestOptions[e] === 'string') requestOptions[e] = parse_url(requestOptions[e]); }); if (!requestOptions.target && !requestOptions.forward) { return this.emit('error', new Error('Must provide a proper URL as target')); } for (var i = 0; i < passes.length; i++) { /** * Call of passes functions * pass(req, res, options, head) * * In WebSockets case the `res` variable * refer to the connection socket * pass(req, socket, options, head) */ if (passes[i](req, res, requestOptions, head, this, cbl)) { // passes can return a truthy value to halt the loop break; } } }; }; }
上面的核心就是遍历passes, 这个passes又是什么呢,
是 web = require(‘./passes/web-incoming’) , 我们再进入看一看
- deleteLength: function deleteLength(req, res, options)
- timeout: function timeout(req, res, options)
- XHeaders: function XHeaders(req, res, options)
- stream: function stream(req, res, options, _, server, clb)
最终发送请求的就是这个stream, passes就是对应这几个东西.
我们再进入steam 方法, 直接看代码27行,实际就是根据protocold调用http或者https的request方法.
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); } }); }
这里简单分析的是http(htttps)的代理走向, socket就靠你们了, 没电了,拜.
以上所述就是小编给大家介绍的《浅浅的说http-proxy-middleware》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Unity Shader入门精要
冯乐乐 / 人民邮电出版社 / 2016-5-1 / CNY 69.00
本书不仅要教会读者如何使用Unity Shader,更重要的是要帮助读者学习Unity中的一些渲染机制以及如何使用Unity Shader实现各种自定义的渲染效果,希望这本书可以为读者打开一扇新的大门,让读者离制作心目中杰出游戏的心愿更近一步。 本书的主要内容为:第1章讲解了学习Unity Shader应该从哪里着手;第2章讲解了现代GPU是如何实现整个渲染流水线的,这对理解Shader的工......一起来看看 《Unity Shader入门精要》 这本书的介绍吧!