http-proxy 实现反向代理

612 阅读2分钟

一般,前端开发去运行一些 jsp 的老项目,是不会本地搭建 jsp 开发环境的。而是在本地开发的时候,通过代理,使用测试环境的 jsp 文件。即是说,本地开发的时候,使用本地的 js,css,html,img 等静态资源文件,使用测试环境的 jsp 和接口。

当然,这种情况最好是 jsp 仅作为一个容器,在需求中变动较少。毕竟本地修改 jsp 是不会生效的。这种架构常见在前后端分离开始那段时间的项目,一般也是 backbone + requireJS 的技术栈居多。

代理的实现有很多中方式。如果是现在,webpack,vue 的配置文件,都有配置代理的功能。但这种老项目,一般就是用 nginx 或者 fiddler 进行代理。这就导致每个新接手的人都要下个 nginx 或者 fiddler,然后从某个团队成员那里要来配置,每次运行这个项目还得先启动一下,过于麻烦。

因此,就有了这样一个方案:用 node 的 http 模块开启服务器,用 http-proxy 转发请求。实现以下功能:

  1. 接口转发,解决跨域问题
  2. 文件代理,开发一些 jsp 的旧项目,可以代理 js, css, image 等静态文件

优点是是可以不用配置 nginx,而用 npm run dev 运行开发环境,使新旧项目有一致的开发体验,同时也更方便交接。

const http = require('http')
const httpProxy = require('http-proxy')
const path = require('path')
const fs = require('fs')

const target = 'http://xxx' // 测试环境地址
const port = 8090
const proxyUrlReg = [
  new RegExp('^/api.*'),
  new RegExp('.*.jsp.*'),
  new RegExp('^/images.*.[png|jpg|gif|jpeg]')
]


const proxy = httpProxy.createProxyServer()

http.createServer(function (req, res) {
  const url = req.url

  /*
   * 正则匹配当前请求路径,判断是否需要代理
   */
  const isProxy = proxyUrlReg.reduce((prev, next) => {
    return prev || next.test(url)
  }, false)

  if (isProxy) {
    proxy.web(req, res, { target })
  } else {
   /*
    * 如果不需要代理,则去掉请求路径的参数,获得资源的地址
    * 直接读取文件内容并返回
    */
    const noParamsUrl = url.replace(/(.*)?.*/, '$1')
    const fileUrl = path.join(__dirname, '../../', noParamsUrl)

    fs.readFile(fileUrl, (err, data) => {
      if (err) {
        res.writeHeader(404, { 'content-type': 'text/html;charset="utf-8"' })
        res.write('<h1>404错误</h1><p>你访问的页面/内容不存在</p>')
        res.end()
      } else {
        res.write(data)
        res.end()
      }
    })
  }

  proxy.on('error', err => {
    console.log(err)
  })

}).listen(port)

console.log('代理已开启...')
console.log(`地址:http://localhost:${port}/`)

代码也非常简单。通过 node 的 http 模块开启一个服务,通过正则表达式匹配需要代理的资源请求,符合正则表达式的资源请求就转发到测试环境,不符合的则读取本地文件内容进行返回。

以上。