• http-proxy-middleware监听并处理返回数据以及禁用缓存


    1、参考文档1:https://github.com/chimurai/http-proxy-middleware#compatible-servers

    2、点开上图链接 https://github.com/http-party/node-http-proxy#listening-for-proxy-events

    If you want to handle your own response after receiving the proxyRes, you can do so with selfHandleResponse. As you can see below, if you use this option, you are able to intercept and read the proxyRes but you must also make sure to reply to the res itself otherwise the original client will never receive any data.

    Modify response

    var option = {
      target: target,
      selfHandleResponse : true
    };
    proxy.on('proxyRes', function (proxyRes, req, res) {
        var body = [];
        proxyRes.on('data', function (chunk) {
            body.push(chunk);
        });
        proxyRes.on('end', function () {
            body = Buffer.concat(body).toString();
            console.log("res from proxied server:", body);
            res.end("my response to cli");
        });
    });
    proxy.web(req, res, option);

    3、参考demo

       通过proxyRes拿到接口的数据后,对数据进行处理

    const proxy = require('http-proxy-middleware');
    const RouterService = require('../service/RouterService.js')
    let target;
    if (!process.env.NODE_ENV) { // 本地测试
        target = "http://xx.xx.xxx.xxx:3000"
    } else {
        target = "http://172.31.xxx.xxx:3000";
    }
    var options = {
        target: target,
        selfHandleResponse: true, // handle your own response after receiving the proxyRes
        changeOrigin: true,
        pathRewrite: {
            '^/api/xx/account': '/account',
            '^/api/xx/strategy_name': '/strategy_name',
            '^/api/xx/strategy_key': '/strategy_key',
            '^/api/xx/stats': '/stats',
            '^/api/xx/type': '/type',
            '^/api/xx/positions': '/positions',
            '^/api/xx/klines': '/klines',
            '^/api/xx/orders': '/orders',
        },
        // 需要监听是否正常发送请求以及接收到响应信息可添加
        // onProxyReq: function(proxyReq, req, res){
        //     console.log("request done")
        // },
        onProxyRes: async function (proxyRes, req, res) {
            // 获取接口返回的数据
            let body = {}
            const responseBody = await getBody(proxyRes)
            if (responseBody) body = responseBody
    
            if (req.url.indexOf('?') > -1) {
                req.url = req.url.substring(0, req.url.indexOf('?'))
            }
    
            // 对api接口的返回值进行过滤
            let data = body.data
            switch (req.url) {
                case '/type':
                    data = await handler(data, 'type', req)
                    break
                case '/account':
                    data = await handler(data, 'account', req)
                    break
                default:
                    break
            }
            body.data = data
    
            // 配置selfHandleResponse : true后,必须通过res响应数据,否则客户端获取不到返回
            // res.end(JSON.stringify(body)) // string或buffer
            res.json(body)
        },
        // onError: function(err, req, res) {
        //     console.log(err)
        // }
    };
    
    /**
     * 从proxyRes获取body数据,返回json对象
     * @param {*} proxyRes 
     * @param {*} res 
     */
    function getBody(proxyRes) {
        return new Promise((resolve, reject) => {
            let body = []
            proxyRes.on('data', function (chunk) {
                body.push(chunk)
            })
            proxyRes.on('end', function () {
                body = Buffer.concat(body).toString()
                // console.log('getBody ======', body)
                resolve(JSON.parse(body))
            })
        })
    }
    
    async function handler(data, apiFilterType, req) {
        // 根据router的pathName查询对应的routerId
        let routerId = 0
        const result = await RouterService.queryRouterByPathName('/api/pnl-v2')
        if (!result.err) routerId = result.id
    
        // 获取当前用户的角色id
        let roleId = 0
        if (req.session && req.session.user && req.session.user.roles)
            roleId = req.session.user.roles[0].id
    
        // 根据routerId和roleId查询`router_role_binding`表记录
        let apiResourceFilter = ''
        const result2 = await RouterService.getFilterItemList(roleId, routerId)
        if (!result2.err) apiResourceFilter = result2.apiResourceFilter
        if (apiResourceFilter) apiResourceFilter = JSON.parse(apiResourceFilter)
        // 1718 505 [{account: ['a', 'b' }, {type: ['mm']}]
        // console.log(routerId, roleId, apiResourceFilter)
    
        return new Promise(resolve => {
            apiResourceFilter.forEach(filterItem => {
                // if (filterItem['type']) {
                if (filterItem[apiFilterType]) {
                    // const typeArray = filterItem['type']
                    const typeArray = filterItem[apiFilterType]
                    // console.log(`typeArray=${JSON.stringify(typeArray)}`)
                    data = data.filter(item => {
                        return typeArray.indexOf(item) > -1
                    })
                }
            })
            resolve(data)
        })
    }
    
    var pnlProxy = proxy(options);
    module.exports = pnlProxy;

    4、代理禁用缓存

      使用过程中发现,连续发两个请求,第二个请求返回代理无法拿到数据

       浏览器禁用缓存,再发两个请求,都没有问题

       解决方法:客户端的请求头加个 cache-control: no-cache

      proxyReq.setHeader('Cache-Control', 'no-cache');

    const proxy = require('http-proxy-middleware')
    const RouterService = require('../service/RouterService.js')
    
    // app.js  app.use("/api/pnl-v2", authChecker, pnlProxy)
    const baseRouterUrl = '/api/pnl-v2'
    
    let target
    if (!process.env.NODE_ENV) { // 本地测试
        target = "http://47.52.xx.xx:3000"
    } else {
        target = "http://172.31.xx.xx:3000"
    }
    const options = {
        target: target,
        selfHandleResponse: true, // handle your own response after receiving the proxyRes
        changeOrigin: true,
        pathRewrite: {
            '^/api/pnl-v2/account': '/account',
            '^/api/pnl-v2/strategy_name': '/strategy_name',
            '^/api/pnl-v2/strategy_key': '/strategy_key',
            '^/api/pnl-v2/stats': '/stats',
            '^/api/pnl-v2/type': '/type',
            '^/api/pnl-v2/positions': '/positions',
            '^/api/pnl-v2/klines': '/klines',
            '^/api/pnl-v2/orders': '/orders',
        },
        // 需要监听是否正常发送请求以及接收到响应信息可添加
        onProxyReq: function(proxyReq, req, res){
            // console.log("request done")
            // 禁用缓存
            proxyReq.setHeader('Cache-Control', 'no-cache');
        },
        onProxyRes: async function (proxyRes, req, res) {
            // 获取接口返回的数据
            let body = {}
            const responseBody = await getBody(proxyRes)
            if (responseBody) body = responseBody
    
            if (req.url.indexOf('?') > -1) {
                req.url = req.url.substring(1, req.url.indexOf('?'))
            }
    
            // 对api接口的返回值进行过滤
            body.data = await filterHandler(body.data, req.url, req)
            res.json(body)
        },
        // onError: function(err, req, res) {
        //     console.log(err)
        // }
    }
    
    /**
     * 从proxyRes获取body数据,返回json对象
     * @param {*} proxyRes 
     * @param {*} res 
     */
    function getBody(proxyRes) {
        let result = {}
        return new Promise(resolve => {
            let body = []
            proxyRes.on('data', function (chunk) {
                body.push(chunk)
            })
            proxyRes.on('end', function () {
                body = Buffer.concat(body).toString()
                try {
                    result = JSON.parse(body)
                } catch (err) {
                    // 未禁用缓存时,第二次请求body为{}
                    console.error('pnlProxy getBody error, body=', body)
                }
                resolve(result)
            })
        })
    }
    
    async function filterHandler(data, apiFilterType, req) {
        if (!data) {
            console.error('filterHandler data is empty')
            return
        }
    
        // 根据router的pathName查询对应的routerId
        let routerId = 0
        const RouterResult = await RouterService.queryRouterByPathName(baseRouterUrl)
        if (!RouterResult.err) routerId = RouterResult.id
    
        // 获取当前用户的角色id
        let roleIdArray = []
        if (req.session && req.session.user && req.session.user.roles) {
            for (let role of req.session.user.roles) {
                roleIdArray.push(role.id)
            }
        }
    
        // 根据routerId和roleId查询`router_role_binding`表记录
        let apiResourceFilterArray = [] // [{account: ['xx', 'xx']}, {type: ['mm', 'cta']}]
        for (let roleId of roleIdArray) {
            const resultTemp = await RouterService.getFilterItemList(roleId, routerId)
            if (!resultTemp.err && resultTemp.apiResourceFilter)
                mergeToArray(JSON.parse(resultTemp.apiResourceFilter), apiResourceFilterArray)
        }
    
        return new Promise(resolve => {
            if (apiResourceFilterArray.length === 0) {
                resolve(data)
                return
            }
    
            apiResourceFilterArray.forEach(filterItem => {
                if (filterItem[apiFilterType]) {
                    const typeArray = filterItem[apiFilterType]
                    data = data.filter(item => {
                        return typeArray.indexOf(item) > -1
                    })
                }
            })
            resolve(data)
        })
    
        function mergeToArray(targetArray, sourceArray) {
            const sourceKeys = sourceArray.map(item => Object.keys(item)[0])
            targetArray.forEach(obj => {
                const index = sourceKeys.indexOf(Object.keys(obj)[0])
                if (index > -1) {
                    let source = Object.values(sourceArray[index])[0]
                    for (let i of Object.values(obj)[0]) {
                        if (source.indexOf(i) === -1) source.push(i)
                    }
                } else {
                    sourceArray.push(obj)
                }
            })
        }
    }
    
    const pnlProxy = proxy(options)
    module.exports = pnlProxy

    ---

    http-proxy-middleware的使用可以参考:http-proxy-middleware使用方法和实现原理(源码解读)

  • 相关阅读:
    C# 关键字 virtual、override和new的用法
    架构技术及架构要素总结【转】
    vue文件目录结构
    vue项目中,如何对static文件夹下的静态文件添加时间戳,以达到清除缓存
    webpack中关于require与import的区别
    vue 根据下拉框动态切换form的rule
    el-select 根据value查询其对应的label值
    web前端项目规范
    JavaScript 编码规范
    HTML 编码规范
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/12108354.html
Copyright © 2020-2023  润新知