热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

httpproxymiddleware监听并处理返回数据以及禁用缓存httpproxymiddleware使用方法和实现原理(源码解读)

#cnblogs_post_bodyimg{max-width:600px;height:auto}1、参考文档1:https:github.comchimuraihttp-pro

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

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

http-proxy-middleware使用方法和实现原理(源码解读)

 

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、代理禁用缓存

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

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

http-proxy-middleware使用方法和实现原理(源码解读)

 

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

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

http-proxy-middleware使用方法和实现原理(源码解读)

 

   解决方法:客户端的请求头加个 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使用方法和实现原理(源码解读)


推荐阅读
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • 标题: ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
author-avatar
Apollo宫保鸡丁
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有