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使用方法和實現原理(源碼解讀)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM