专栏首页京程一灯手写可配置的express nodejs的代理

手写可配置的express nodejs的代理

nodejs比较好的代理包有:node-http-proxy和http-proxy-middleware。这两个我都用过,它们的优点自不用说,只说说缺点:它们不能从配置文件里读取代理配置。每添加一个拦截路径都需要多加一个接口调用。

所以,我需要自己写一个http代理,要包含一下功能:

  1. 从配置文件里读取代理配置
  2. 可以路径重写

这样做的好处是:新增服务只需要在配置文件上加上该服务,无需修改业务逻辑

1 /config/default.js

  1. module.exports = {
  2. "ENV":"dev",
  3. "PORT":"8088",
  4. "maxAge": 10,
  5. "proxy":{
  6. "olap":{
  7. "host":"172.16.200.225",
  8. "port":"8092",
  9. "form":"",
  10. "to":""
  11. },
  12. "qc":{
  13. "host":"192.168.40.231",
  14. "port":"30088"
  15. },
  16. "api":{
  17. "host":"192.168.40.231",
  18. "port":"30412"
  19. },
  20. "ocm":{
  21. "host": process.env.ocm_host || "192.168.40.119",
  22. "port": process.env.ocm_port || "31003"
  23. }
  24. }
  25. }
2 /app.js

将所有要走代理的路径前必需加上 /p, 这个是我的个人配置,当然也可以是其他的名字。

  1. var express = require('express');
  2. var compression = require('compression');
  3. var path = require('path');
  4. var config = require('config');
  5. var log4js = require('log4js');
  6. var wsProxyConfig = config.get('proxy');
  7. var routes = require('./routes/index');
  8. var views = require('./routes/views');
  9. var proxy = require('./routes/proxy');
  10. app.use('/p',proxy);
3 /routes/proxy.js
  1. var express = require('express');
  2. // config是一个第三方包,它的功能是
  3. // 自动根据环境变量帮你读取config目录下
  4. // 的配置文件,默认会读取default.json,
  5. // config支持很多文件类型。
  6. var config = require('config');
  7. var request = require('request');
  8. var log4js = require('log4js');
  9. var path = require('path');
  10. var router = express.Router();
  11. // 此处就是获取配置文件的proxy项了
  12. var proxyConfig = config.get('proxy');
  13. // 这里记录代理的日志
  14. log4js.configure({
  15. appenders: [
  16. {
  17. type: 'file',
  18. filename: './logs/all-proxy-logs.log',
  19. maxLogSize: 10*1024*1024, //max 10mb
  20. backups: 5,
  21. compress: true
  22. },
  23. {
  24. type: 'stdout'
  25. }
  26. ]
  27. });
  28. var logger = log4js.getLogger('proxy');
  29. router.all('/:apiName/*', function(req, res, next) {
  30. // apiName 必需要对应配置文件的proxy的属性名
  31. var apiName = req.params.apiName;
  32. if(!apiName){
  33. res.status(404).end('api not found');
  34. }
  35. // 如果apiName不在配置文件里,则报500
  36. else if(!proxyConfig[apiName]){
  37. res.status(500).end('api has no config');
  38. }
  39. else{
  40. // originUrl是原始的url
  41. // 例如 /p/qc/calls
  42. var originalUrl = req.originalUrl;
  43. var api = proxyConfig[apiName];
  44. var url = originalUrl.replace('/p','');
  45. url = `http://${api.host}:${api.port}` + url;
  46. // 某些需要路径重写的地方
  47. if(api.form && api.to){
  48. url = url.replace(api.form, api.to);
  49. }
  50. // 必须要删除这个host
  51. // 因为本地测试时,这个host是localhost
  52. // 这会导致服务端报错
  53. delete req.headers.host;
  54. // 修改好的请求头
  55. var option = {
  56. url: url,
  57. headers: req.headers
  58. };
  59. // 使用request发起请求
  60. var proxy = request(option);
  61. // 此处是关键,将请求流写入代理,将代理的响应写入原始响应
  62. req.pipe(proxy);
  63. proxy.pipe(res);
  64. // 代理结束响应时,原始请求结束,并输出日志
  65. proxy.on('end', function(){
  66. var log = `${req.method} ${res.statusCode} ${req.originalUrl} ---> ${option.url} ${req.headers.sessionid}`;
  67. if(res.statusCode < 400){
  68. logger.info(log);
  69. }
  70. else{
  71. logger.error(log);
  72. }
  73. res.end();
  74. });
  75. }
  76. });
  77. module.exports = router;
4 相关第三方模块
  • node-config
  • request
  • log4js-node

往期精选文章

使用虚拟dom和JavaScript构建完全响应式的UI框架

扩展 Vue 组件

使用Three.js制作酷炫无比的无穷隧道特效

一个治愈JavaScript疲劳的学习计划

全栈工程师技能大全

WEB前端性能优化常见方法

一小时内搭建一个全栈Web应用框架

干货:CSS 专业技巧

四步实现React页面过渡动画效果

让你分分钟理解 JavaScript 闭包



小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

本文分享自微信公众号 - 京程一灯(jingchengyideng)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-09-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • LPI学习笔记----1

    上面是建立了三个任务,并且都ctrl+z给stop掉了,然后用jobs查看,一共有三个stop的任务

    用户3765803
  • 用beego vue.js element axios 写flow办公流程——系列五

    自己的认识:一定要用独立的前端,即vue.js前端项目必须是独立的,独立的服务,不要放beego里的view里作为tpl页面。虽然,放beego view里的t...

    hotqin888
  • vue-cli3项目创建-配置-发布

    (2) 修改user module -- src/store/module/user.js

    RtyXmd
  • Linux硬链接与软链接

    在Linux中,连接文件有两种,一种类似于Windows的快捷方式,可以让你快速地链接到目标文件(或目录),这种称为软链接(soft link),也叫作符号链接...

    Dabelv
  • macOS Mojave 10.14安装nvm

    nodejs的版本迭代非常快速, 时至今日(2019年2月7日), nodejs的最新版本是11.

    zhaoolee
  • 微信小程序wepy框架入门教程(一)

    端开发框架和环境都是需要 Node.js ,先安装node.js开发环境,WePY借鉴了Vue.js(后文简称Vue)的语法风格和功能特性,vue的运行是要依赖...

    祈澈菇凉
  • 「实战篇」开源项目docker化运维部署-借助dockerSwarm搭建集群部署(九)

    为了让学习的知识融汇贯通,目前是把所有的集群都放在了一个虚拟机上,如果这个虚拟机宕机了怎么办?俗话说鸡蛋不要都放在一个篮子里面,把各种集群的节点拆分部署,应该把...

    IT故事会
  • Linux索引节点inode

    理解inode,要从文件储存说起。文件储存在硬盘上,硬盘的最小存储单位叫做”扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。操作系统读取硬盘...

    Dabelv
  • 认识ROS

    1.节点(node)--软件模块 执行任务的进程 2.节点管理器(ROS Master)控制中心,提供参数管理 记录每个节点信息 3.话题(topic)...

    小飞侠xp
  • 第十八节 netty源码分析之 pipleline和handler以及pipeline的数据流向02

    下面是AbstractNioChannel的fulfillConnectPromise具体如下,

    用户1418372

扫码关注云+社区

领取腾讯云代金券