zoukankan      html  css  js  c++  java
  • 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使用方法和实现原理(源码解读)

  • 相关阅读:
    LA 2038 Strategic game(最小点覆盖,树形dp,二分匹配)
    UVA 10564 Paths through the Hourglass(背包)
    Codeforces Round #323 (Div. 2) D 582B Once Again...(快速幂)
    UVALive 3530 Martian Mining(贪心,dp)
    UVALive 4727 Jump(约瑟夫环,递推)
    UVALive 4731 Cellular Network(贪心,dp)
    UVA Mega Man's Mission(状压dp)
    Aizu 2456 Usoperanto (贪心)
    UVA 11404 Plalidromic Subsquence (回文子序列,LCS)
    Aizu 2304 Reverse Roads(无向流)
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/12108354.html
Copyright © 2011-2022 走看看