webpack配置proxy反向代理的原理是什么?

在webpack中配置反向代理可以像这样:

devServer: {
    ...
    proxy: {
        '/api': {
            target: 'http://xxx.xx.xxx.xxx:xxxx'
        },
        changeOrigin: true
    },
    ...
}

但是最近,在做数据对接的时候,由于后端的接口并不是放在一个地方,导致我这儿要写2个proxy,那就要匹配2个关键字,比如像下面这样:

devServer: {
    ...
    proxy: {
        '/api/a': {
            target: 'http://xxx.xx.xxx.xxx:xxxx'
        },
        '/api/b': {
            target: 'http://zzz.zz.zzz.zzz:zzz'
        },
        changeOrigin: true
    },
    ...
}

但问题是,'/api/a'中的 a'/api/b' 中的 b 都是不定的。后端同学说,因为它们都隶属于不同的项目,前端总不能限定后端的接口url规则吧?

想了一下,好像也有点道理。可是问题就在于如果 ab 都是不定的,那不就等于要匹配的是'/api/'嘛?那我的target 要怎么分别指向2个不同的地址呢?

所以,求助大神,proxy的反向代理的原理到底是什么?遇到这样的问题,我该怎么解决呢?

阅读 956
评论 2018-12-25 提问
    4 个回答
    micherwa
    • 5.1k

    前端webpack中的proxy只是一层代理,用于把指定的path,代理去后端提供的地址,它的背后是由node来做server。

    举个简单的例子:
    前端请求 服务器a,然后就得到了想要的数据。但其实 服务器a 中本身没有部署任何接口,它只是偷偷地从 服务器b 上取来数据,返回给前端。这个过程只在server端发生,前端是无感知的。

    我们说的反向代理,其实在后端看来,有两层意思。代理是前提,实现负载均衡才是目的。负载均衡,是为了把请求分发到不同的服务器,从而减轻了单个服务器处理海量数据的压力。

    所以,回到这个问题中来。

    webpack的 proxy 基于http-proxy-middleware的规则,只能根据不同的path才能做代理,解决跨域问题。

    所以,用刚才的 服务器a 的例子,可以让后端同学,在 服务器a上做一些处理,使得前端可以根据不同的path,代理去不同的domain。好好沟通,应该是可以实现的。

    评论 赞赏 2018-12-27

      很急。。求助大神指点!

      评论 赞赏 2018-12-26
        沼泽
        • 890

        这样的写法呢

            proxy: {
                '/api1': {
                    target: 'http://xxx.xx.xxx.xxx:xxxx'
                },
                '/api2': {
                    target: 'http://zzz.zz.zzz.zzz:zzz'
                },
                changeOrigin: true
            }
        评论 赞赏 2018-12-26
          刘志平
          • 1
          • 新人请关照

          可以这样解决吧(需要包装接口):

          config.js (用于定制化配置,解决开发环境和生产环境的不同)
          这个文件一般不会上传到远程仓库(repository)
          代替上传到 repository 的是一份试样(sample)文件 - config.js.sample
          这样就能使得各个开发环境和生产环境都各有自己的配置

          // config.js 开发环境
          module.exports = {
              backend1: {
                  path: '/v1',
                  url: 'http://xxx.xx.xxx.xxx:xxxx',
              },
              backend2: {
                  path: '/v2',
                  url: 'http://zzz.zz.zzz.zzz:zzz',
              },
              // ...其他配置
          }
          
          // config.js 生产环境
          module.exports = {
              backend1: {
                  path: '/',
                  url: '',
              },
              backend2: {
                  path: '/',
                  url: '',
              },
          }

          apiConvert 函数,用于转换请求的 api,如:

          const config = require('config.js')
          function apiConvert(api, type){
              return config[`backend${type}`].path.replace(/\/*$/, '') + api.replace(/^\/*/, '/')
          }
          
          apiConvert('api/a', 1) // => '/v1/api/a'(开发环境) 
          apiConvert('api/a', 1) // => '/api/a'(生产环境)

          devServer 配置

          const config = require('config.js')
          const devServer = {
              // ...
              proxy: {
                  [config.backend1.path]: {
                      target: config.backend1.url
                  },
                  [config.backend2.path]: {
                      target: config.backend2.url
                  },
                  changeOrigin: true
              },
              // ...
          }

          刘志平 - livelybone
          github - 个人组件库 - Demo

          评论 赞赏 2019-03-07
            撰写回答

            登录后参与交流、获取后续更新提醒