一、跨域分类
跨域分为开发跨域(开发环境跨域)和线上跨域(生产环境跨域):
- 开发环境跨域:开发阶段前后端工作站不同,所以ip地址不同,请求数据必然出现跨域问题;
- 生产环境跨域:一个网站关联多台服务器产生的跨域问题,构成一个完整的生产服务器集群,生产服务器集群之间的通信通过地址的方式通信,就算在局域网中,端口地址也是不一样的。
二、解决
2.1 线上跨域
线上跨域的常规解决方案:
- 后端代码上增加一个跨域请求响应头:Access-Control-Allow-Origin
例如:php中的header(Access-Control-Allow-Origin:*) ;PS:其中,*表示所有请求地址都可允许跨域响应
- 也可以采用 前后端配置处理 的方式:采用jsonp模式,前端完成jsonp请求发送
2.2 开发跨域
即:在开发过程中存在的跨域问题,这种现象一般出现在 前后端分离的项目中:前后端分离导致开发联调过程中不在同一服务器或端口下,引发的跨域。
开发阶段引发的跨域可能在项目上线时消失,即当前端代码打包到后端同一服务器上,此时地址相同端口相同,相当于所有的接口都是在同一服务器内部进行请求调用操作,因此便不会产生跨域。但是呢,没有开发哪儿来的上线,因此还是免不了开发过程中的跨域。
解决方式:前端构建代理服务器来完成跨域。即:在本地创建一个虚拟服务器,发送请求数据,同时接收请求的数据
过程:
- 在vue.config.js配置文件中,通过devServer.proxy选项配置代理:
devServer:{ port: 8080, proxy: { // key:描述项目中哪些请求需要被代理服务器代理,以路径前缀方式描述key,定义被拦截请求的前缀 "/api": { target: "http://127.0.0.1:8080", // 定义被拦截的请求需要访问的真实服务器 pathRewrite: { // 通过前缀替换进行地址的重写和定义:去掉/api(因为/api默认会拼接上去) "^/api": "" // 替换掉以/api开头的,这里用空字符串替换,直接去掉 } } } }
原理:当遇到“/api”时,会进入内部函数,将target变量的真实后台地址拼接到“/api”的前面,此时 请求路径变成了:“http://127.0.0.1:8080/api",然后由于pathRewrite方法中将 “/api”替换成了空,也就是说直接去掉,因此路径变成了 ““http://127.0.0.1:8080”,这就完成了代理,通过“/api”这个桥梁将后台地址成功地引入。
注:
vue.config.js文件只是做前端代理解决跨域问题时所用到的配置文件,当前端打包到服务器上时,该文件会被忽略,因此前端对于 api接口路径的定义一定要跟后端所提供的保持一致,不能随意增减上下文,即使你可能通过 配置代理 获取了正确的请求路径,因为打包到服务器后代理便失效了。
三、实例
1、当前需请求的后端接口路径:
192.168.88.88:8091/host/getHostsInfo
2、配置文件
devServer:{ port: 8080, //代表本地服务器启动后的虚拟端口 proxy: { "^/host": { // ^/host 表示匹配查询以host开头的路径, /host有可能查询到路径中包含host的,不一定作为开头 target: "http://192.168.88.88:8091", // 定义被拦截的请求需要访问的真实服务器 pathRewrite: { // 通过前缀替换进行地址的重写和定义:去掉/host(因为/host默认会拼接上去) "^/host": "/host" // 替换掉以/host开头的,这里只是为了展示pathRewrite的用法,不需替换可以直接去掉这段。 } } } }
3、创建axios的时候,baseUrl配置:
const ajax = axios.create({ baseURL:"", timeout: 6000,//请求超时时间 })
创建请求:
export function getData() { //get return request({ url: '/host/getHostsInfo', method: 'GET' }) }
此时,baseUrl拼上请求地址,得到:/host/getHostsInfo,在代理proxy函数中,遇到 /host,则代理到target下的真实服务器路径,将target的真实服务器地址加到 /host 前面,因此得到:http://192.168.88.88:8091/host/getHostsInfo ,也就是真实需请求的后端真实服务器接口路径地址。
而如果在pathRewrite中对路径进行了重写,将 /host 替换成 "" 空字符串,即去掉它,此时代表后端接口请求路径:http://192.168.88.88:8091/getHostsInfo。当然,本实例中这样的代理是调不通的~
四、当项目需请求不同的后端地址时候,可配置多个代理。
原理一样,直接上代码:
proxy:{ "/api": { target: "http://192.168.88.88:8091", // ws: true, // 是否启用websockets changeOrigin: true pathRewrite: { "^/api": "" } }, "/user": { target: "http://192.168.99.99:8091", // ws: true, changeOrigin: true pathRewrite: { "^/user": "" } }, },
baseUrl配置:
const ajax = axios.create({ baseURL:"/", //注意:这里我baseUrl写的是 / ,因此在请求接口里的url没有以 / 开头了,写法随意,原理就是一个拼接过程。 timeout: 6000,//请求超时时间 })
请求接口:
export function getData() { //get return request({ url: 'api/host/getHostsInfo', method: 'GET' }) } export function getData1() { //get return request({ url: 'user/host/getHostsInfo', method: 'GET' }) }
此时,上面两种方式最终请求的真实服务器接口路径 是 两台服务器下的同一接口路径:
http://192.168.88.88:8091/host/getHostsInfo
http://192.168.99.99:8091/host/getHostsInfo