UNPKG

3.65 kBJavaScriptView Raw
1/**
2 * http代理中间件 匹配代理、请求重定向
3 * 获取app.config.js配置文件,匹配proxy
4 */
5const path = require('path')
6const urlUtils = require('url')
7const koaHttpProxy = require('koa-better-http-proxy')
8const compose = require('koa-compose')
9const { IS_DEBUG } = require('./../utils/env')
10const logger = require('./../logger/koa-logger')('proxyMiddleWare')
11const appConfig = require(path.join(process.cwd(), 'app.config'))
12const needToken = !!appConfig.token
13let tokenManager
14if (needToken) {
15 tokenManager = require('./token')(appConfig.token)
16}
17/**
18 * 代理处理中间件
19 * @return {Function} koa middleware
20 */
21module.exports = function () {
22 async function preProxyMiddleware(ctx, next) {
23 const url = ctx.url
24 const staticRequest = url.startsWith('/api')
25 logger.info(`Request '${url}'`)
26 let proxyTarget
27 let proxyConfig = appConfig.proxy
28 // 在appConfig.proxy中寻找匹配前缀的代理
29 for (const [prefix, target] of Object.entries(proxyConfig)) {
30 if (url.startsWith(prefix)) {
31 // 匹配替换
32 if (staticRequest) ctx.url = url.replace(prefix, '')
33 proxyTarget = target
34 ctx._proxyTarget = proxyTarget
35 break
36 }
37 }
38 if (!proxyTarget) {
39 logger.info('Proxy not found, skipped')
40 return Promise.resolve()
41 }
42 logger.info(`Will be Agent to '${proxyTarget + ctx.url}'`)
43 return next()
44 }
45
46 /**
47 * 顺序执行async函数
48 */
49 return compose([
50 preProxyMiddleware,
51 koaHttpProxy(
52 (ctx) => {
53 return ctx._proxyTarget
54 },
55 {
56 // 不解析body,不限制body大小
57 parseReqBody: false,
58 /**
59 * 发出代理请求前的回调,更改头文件
60 * @param {Object} proxyReqOpts - 代理请求选项
61 * @param {ctx} ctx - koa ctx
62 * @return {Promise.<*>} *
63 */
64 async proxyReqOptDecorator(proxyReqOpts, ctx) {
65 const parsedTarget = urlUtils.parse(ctx._proxyTarget, true)
66 proxyReqOpts.host = parsedTarget.hostname
67 proxyReqOpts.port = parsedTarget.port
68 proxyReqOpts.https = parsedTarget.protocol === 'https:'
69
70 // 去掉Referer头,否则可能会造成CSRF问题,影响开发
71 if (IS_DEBUG) {
72 delete proxyReqOpts.headers.Referer
73 delete proxyReqOpts.headers.Origin
74 }
75 // 计时开始
76 ctx._proxyStartTime = Date.now()
77 if (!needToken) {
78 return proxyReqOpts
79 }
80 return await tokenManager.handleRequest(ctx)
81 .then((additionalHeaders) => {
82 Object.assign(proxyReqOpts.headers, additionalHeaders)
83 })
84 .then(() => {
85 return proxyReqOpts
86 })
87 },
88 /**
89 * 代理请求被响应后的回调
90 * @param {Response} proxyRes - 代理请求选项
91 * @param {Object} proxyResData - 响应数据
92 * @param {ctx} ctx - koa ctx
93 * @return {Promise.<*>} *
94 */
95 async userResDecorator(proxyRes, proxyResData, ctx) {
96 logger.info('Interface ProxyRes headers:', '\n', JSON.stringify(ctx.response.headers, null, 2))
97 const location = `${ctx._proxyTarget}${ctx.url}`
98 logger.info(`Interface Proxy request '${location}' completed(${proxyRes.statusCode}), costing ${Date.now() - ctx._proxyStartTime}ms.`)
99 if (!needToken) {
100 return proxyResData
101 }
102 return await tokenManager.handleResponse(ctx)
103 .then(() => {
104 return proxyResData
105 })
106 },
107 }),
108 ])
109}