起因 这段时间公司进行了前后端的分离,分离开发是如丝般顺滑了,但是却带来一个问题,接口的跨域,会在调试中带来麻烦。 现阶段接口跨域的 3 中方式。 1.jsonp 2.cors 3.代理 代理(英语:Proxy)也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。
代理分类 1.正向代理 正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
2.反向代理 反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
图解代理
正向代理即是客户端代理, 代理客户端, 服务端不知道实际发起请求的客户端。 反向代理即是服务端代理, 代理服务端, 客户端不知道实际提供服务的服务端。 如果以上没看明白可以看下面:正向代理 :我想去买小明水果,但是我自己懒得去买,我通过一个中介的去帮我跑腿买,即是正向代理,小明水果并不需要知道,我来买水果了。
反向代理 :而在反向代理中,我想吃苹果,我还是懒得去买,但是我和中介说,我想吃苹果,我不关心吃什么苹果,你只要给我拿到一个苹果。
项目中的代理
http-proxy-middleware 这个插件正是我们公司在项目中用到的代理插件,他支持 connect, express and browser-sync,应该来说非常方便,下面是他的使用方式。
1 2 3 4 5 6 7 var express = require ('express' );var proxy = require ('http-proxy-middleware' );var app = express ();app.use ('/api' , proxy ({target : 'http://www.example.org' , changeOrigin : true })); app.listen (3000 );
查看他的部分源码
1 2 3 4 5 6 7 8 9 10 11 var _ = require ('lodash' )var httpProxy = require ('http-proxy' )var configFactory = require ('./config-factory' )var handlers = require ('./handlers' )var contextMatcher = require ('./context-matcher' )var PathRewriter = require ('./path-rewriter' )var Router = require ('./router' )var logger = require ('./logger' ).getInstance ()var getArrow = require ('./logger' ).getArrow ...省略 module .exports = HttpProxyMiddleware
通过看到他的代码得知他用到了 http-proxy 这个库。
http-proxy 那我们就来看 http-proxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var http = require ('http' ), httpProxy = require ('http-proxy' ); var proxy = httpProxy.createProxyServer ({});var server = http.createServer (function (req, res ) { proxy.web (req, res, { target : 'http://127.0.0.1:5060' }); }); console .log ("listening on port 5050" )server.listen (5050 );
目录结构
http-proxy.js
1 2 3 4 5 6 7 8 9 10 11 12 13 var ProxyServer = require ('./http-proxy/index.js' ).Server ;function createProxyServer (options ) { return new ProxyServer (options); } ProxyServer .createProxyServer = createProxyServer;ProxyServer .createServer = createProxyServer;ProxyServer .createProxy = createProxyServer;module .exports = ProxyServer ;
./http-proxy/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 var httpProxy = module .exports , extend = require ('util' )._extend , parse_url = require ('url' ).parse , EE3 = require ('eventemitter3' ), http = require ('http' ), https = require ('https' ), web = require ('./passes/web-incoming' ), ws = require ('./passes/ws-incoming' ); httpProxy.Server = ProxyServer ; function createRightProxy (type ) { return function (options ) { return function (req, res ) { var passes = (type === 'ws' ) ? this .wsPasses : this .webPasses , args = [].slice .call (arguments ), cntr = args.length - 1 , head, cbl; if (typeof args[cntr] === 'function' ) { cbl = args[cntr]; cntr--; } var requestOptions = options; if ( !(args[cntr] instanceof Buffer ) && args[cntr] !== res ) { requestOptions = extend ({}, options); extend (requestOptions, args[cntr]); cntr--; } if (args[cntr] instanceof Buffer ) { head = args[cntr]; } ['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++) { if (passes[i](req, res, requestOptions, head, this , cbl)) { break ; } } }; }; } httpProxy.createRightProxy = createRightProxy; 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 ); } require ('util' ).inherits (ProxyServer , EE3 );
结构
ProxyServer.createServer
创建使用ProxyServer.createServer
等价 createProxyServer
createProxyServer
返回一个 ProxyServer
实例
ProxyServerProxyServer
拥有 web 属性 web 属性 createRightProxy
支持 http
, https
, webscoket
轮询方法 deleteLength
, 设置 content-length
timeout
XHeaders
stream
核心方法 处理 http.request
核心模块 pipe
response
下面列出来他的核心方法。
带你动手撸一个 以下是我们代理的主要流程思路。
api.js
1 2 3 4 5 6 7 8 9 const http = require ('http' );http.createServer (function (request, response ) { response.writeHead (200 , { 'Content-Type' : 'text/plain' }); response.write (JSON .stringify ({huayifeng : 1 })); response.end (); }).listen (8081 , '127.0.0.1' );
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const http = require ('http' );http.createServer (function (req, res ) { proxy (req, res); }).listen (8080 , '127.0.0.1' ); function proxy (req, res ) { const options = { hostname : '127.0.0.1' , port : 8081 , path : '/' , method : 'GET' , }; const proxyReq = http.request (options); proxyReq.on ('error' , function (e ) { console .log ('problem with request: ' + e.message ); }); proxyReq.on ('response' , function (proxyRes ) { proxyRes.on ('end' , function ( ) { console .log ('end' ); }); proxyRes.pipe (res); }) proxyReq.end (); }
以上就简易实现了一个代理。当你访问 localhost:8080 请求已经被代理到 localhost:8081 了。