前后端分离模式下,前端在开发阶段利用 mock
服务降低了对后台的依赖,到了联调阶段,突然发现所有请求都跨域了,这时候有两条路:
让后台开启跨域支持
前端通过代理支持跨域
这里要讲的就是第二条路,由于项目是基于 vue-cli
构建的,所以通过 webpack
的 devServer.proxy
来实现跨域支持。
devServer.proxy 简介 先简单介绍一下 devServer.proxy
的用法:
注: 这里的 devServer.proxy
就是 vue-cli
中位于 /config/index.js
的 dev.proxyTable
,后面不再赘述
基础用法 在 localhost:3000
上有后端服务的话,你可以这样启用代理:
1 2 3 4 5 6 7 8 9 10 11 module .exports = {... devServer : { proxy : { '/api' : 'http://localhost:3000' } } ... }
这时请求 /api/users
会被代理到请求 http://localhost:3000/api/users
重写路径 如果你不想始终传递 /api
,则需要重写路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module .exports = {... devServer : { proxy : { '/api' : { target : 'http://localhost:3000' , pathRewrite : { '^/api' : '' } } } } ... }
这时请求 /api/users
会被代理到请求 http://localhost:3000/users
HTTPS 支持 默认情况下,不接受运行在 HTTPS
上,且使用了无效证书的后端服务器。如果你想要接受,修改配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 module .exports = {... devServer : { proxy : { '/api' : { target : 'https://other-server.example.com' , secure : false } } } ... }
选择性代理 有时你不想代理所有的请求。可以基于一个函数的返回值绕过代理。
在函数中你可以访问请求体、响应体和代理选项。必须返回 false
或路径,来跳过代理请求。
例如:对于浏览器请求,你想要提供一个 HTML
页面,但是对于 API
请求则保持代理。你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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
属性的对象」构成的数组:
1 2 3 4 5 6 7 8 9 10 11 12 module .exports = {... devServer : { proxy : [{ context : ['/auth' , '/api' ], target : 'http://localhost:3000' , }] } ... }
跨域支持 大部分情况都会涉及跨域问题,我们可以通过设置 changeOrigin: true
实现跨域支持:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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"'
,我们改造一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ... module .exports = merge (prodEnv, { NODE_ENV : '"development"' , BASE_API : '"/"' }) ... module .exports = { dev : { ... proxyTable : { '/api' : { target : 'http://your-api-server:port/' , changeOrigin : true } }, ... }, ... }
这样就实现了前后端联调时出现的跨域问题
我们完善一下,通过命令行传参来实现 mock
地址和联调地址的切换
1 2 3 4 5 6 7 8 9 { ... "scripts" : { ... "api" : "npm run dev --api" } , ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... module .exports = { dev : { ... proxyTable : { '/api' : { target : process.env .npm_config_api ? 'http://your-api-server:port/' : 'http://your-mock-server:port/' , changeOrigin : true } }, ... }, ... }
我们自己开发时运行 npm run dev
,前后端联调时运行 npm run api
参考资料 webpack 官网 devServer.proxy 配置 http-proxy-middleware