前后端分离模式下,前端在开发阶段利用 mock 服务降低了对后台的依赖,到了联调阶段,突然发现所有请求都跨域了,这时候有两条路:
- 让后台开启跨域支持
- 前端通过代理支持跨域
这里要讲的就是第二条路,由于项目是基于 vue-cli 构建的,所以通过 webpack 的 devServer.proxy 来实现跨域支持。
devServer.proxy 简介
先简单介绍一下 devServer.proxy 的用法:
注: 这里的 devServer.proxy 就是 vue-cli 中位于 /config/index.js 的 dev.proxyTable,后面不再赘述
基础用法
在 localhost:3000 上有后端服务的话,你可以这样启用代理:
// webpack.config.js
module.exports = {
...
devServer: {
proxy: {
'/api': 'http://localhost:3000'
}
}
...
}
这时请求 /api/users 会被代理到请求 http://localhost:3000/api/users
重写路径
如果你不想始终传递 /api ,则需要重写路径:
// webpack.config.js
module.exports = {
...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api' : '' } // remove base path
// pathRewrite: { '^/api' : '/api/new-path' } // rewrite path
}
}
}
...
}
这时请求 /api/users 会被代理到请求 http://localhost:3000/users
HTTPS 支持
默认情况下,不接受运行在 HTTPS 上,且使用了无效证书的后端服务器。如果你想要接受,修改配置如下:
// webpack.config.js
module.exports = {
...
devServer: {
proxy: {
'/api': {
target: 'https://other-server.example.com',
secure: false
}
}
}
...
}
选择性代理
有时你不想代理所有的请求。可以基于一个函数的返回值绕过代理。
在函数中你可以访问请求体、响应体和代理选项。必须返回 false 或路径,来跳过代理请求。
例如:对于浏览器请求,你想要提供一个 HTML 页面,但是对于 API 请求则保持代理。你可以这样做:
// webpack.config.js
module.exports = {
...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
bypass: function(req, res, proxyOptions) {
if (req.headers.accept.indexOf('html') !== -1) {
console.log('Skipping proxy for browser request.');
return '/index.html';
}
}
}
}
}
...
}
代理多个路径
如果你想要代理多个路径特定到同一个 target 下,你可以使用由一个或多个「具有 context 属性的对象」构成的数组:
// webpack.config.js
module.exports = {
...
devServer: {
proxy: [{
context: ['/auth', '/api'],
target: 'http://localhost:3000',
}]
}
...
}
跨域支持
大部分情况都会涉及跨域问题,我们可以通过设置 changeOrigin: true 实现跨域支持:
// webpack.config.js
module.exports = {
...
devServer: {
proxy: {
'/api': {
target: 'https://other-server.example.com',
changeOrigin: true
}
}
}
...
}
基于 vue-cli 的跨域处理
回到最开始的问题,基于 vue-cli 的跨域处理,我们只要将上述相关配置写到 /config/index.js 的 dev.proxyTable 中即可,唯一需要注意的问题是我们可能在 /config/dev.env.js 中配置了 BASE_API: '"http://your-mock-server:port"',我们改造一下:
// /config/dev.env.js
...
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '"/"'
})
// /config/index.js
...
module.exports = {
dev: {
...
proxyTable: {
'/api': {
target: 'http://your-api-server:port/', // 后端服务地址
changeOrigin: true
}
},
...
},
...
}
这样就实现了前后端联调时出现的跨域问题
我们完善一下,通过命令行传参来实现 mock 地址和联调地址的切换
// /package.json
{
...
"scripts": {
...
"api": "npm run dev --api"
},
...
}
// /config/index.js
...
module.exports = {
dev: {
...
proxyTable: {
'/api': {
// 通过命令区分后端服务地址和 mock 地址
target: process.env.npm_config_api ? 'http://your-api-server:port/' : 'http://your-mock-server:port/',
changeOrigin: true
}
},
...
},
...
}
我们自己开发时运行 npm run dev,前后端联调时运行 npm run api