• 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使用方法和实现原理(源码解读)

  • 相关阅读:
    补交20145226蓝墨云班课 -- 程序设计中临时变量的使用
    补交20145226蓝墨云班课 -- MyCP
    补交20145226蓝墨云班课 -- MyOD
    补交20145226蓝墨云班课 -- Arrays和String单元测试
    补交20145226蓝墨云班课 -- 后缀表达式
    20145226夏艺华 《Java程序设计》 课堂实践
    20145226夏艺华 网络对抗技术 EXP9 web安全基础实践
    (转载)充分理解QML的属性绑定
    (转载)UML类图中的六大关系:关联、聚合、组合、依赖、继承、实现
    (转载)链路层MTU的概念?为什么MTU值普遍都是1500?
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/12108354.html
Copyright © 2020-2023  润新知