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的反向代理的原理到底是什么?遇到这样的问题,我该怎么解决呢?

阅读 9.6k
4 个回答

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

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

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

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

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

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

很急。。求助大神指点!

这样的写法呢

    proxy: {
        '/api1': {
            target: 'http://xxx.xx.xxx.xxx:xxxx'
        },
        '/api2': {
            target: 'http://zzz.zz.zzz.zzz:zzz'
        },
        changeOrigin: true
    }

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

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

推荐问题
宣传栏