什么是跨域
首先,要明白什么是同源策略。同源就是指协议、域名、端口都要相同,其中任何一个不同都会出现跨域。例如:
http://www.baidu.com:8000
// http 是协议
// www.baidu.com 是域名
// 8000 是端口
跨域问题,是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
同源策略限制了以下行为
- 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
- 无法接触非同源网页的 DOM
- 无法向非同源地址发送 AJAX 请求
当我们开发完前端一个功能之后,需要进行调试 ,通常前后端分离情况下,两套程序都运行起来之后,肯定会出现协议、域名、端口不一致的形况。(H5运行在本地,后端代码又运行另外一台机器上)
那么前端调用后端接口时就会产生跨域问题。
跨域的解决方案
解决跨域的方案有很多,比如:jsonp、cors、Node代理、nginx反向代理。
vue中的proxy就是利用了Node代理。
vue proxy代理解决跨域
原理:通过请求本地的服务器,然后本地的服务器再去请求远程的服务器(后端部署接口的服务器),最后本地服务器再将请求回来的数据返回给浏览器(本地服务器和浏览器之前不存在跨域)
关键点在于:
- 本地服务器(利用node.js创建的本地服务器进行代理,也叫代理服务器)和浏览器之间不存在跨域
- 服务器和服务器之间不存在跨域
proxy配置
我们知道,前端axios在本地发送的请求如果你不把路径写全,它都是会默认加上自己项目所在的端口,就比如说:
axios.get(‘/login’)
当发送之后,以上代码实际请求为:
http://localhost:8080/login
其中 localhost:8080就是自己项目所在的地址了。实际前端就会根据以上的地址来访问后端程序了。
假如我现在想请求后端的 一个接口,例如:http://www.aaabbbccc.com/login,这样我们应该怎样配置代理服务器呢?以vue cli3.0为例:
// vue.config.js
devServer: {
//开启代理服务器
proxy:{
"/api": {
// /api是自行设置的请求前缀,按照这个来匹配请求,有这个字段的请求,就会走到代理来。
target: "http://www.aaabbbccc.com", // 需要代理的域名,目标域名,会替换掉匹配字段之前的路径
ws: false, // 是否启用websockets
changeOrigin: true, //控制服务器接收到的请求头中host字段的值
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
changeOrigin默认值为false,但我们一般将changeOrigin值设为true
*/
pathRewrite: {
//去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
"^/api": ""
}
},
},
}
//vue cli2 .0 的放在 config文件夹中的index.js 中
dev: {
proxyTable:{
"/api": {
target: "http://www.aaabbbccc.com", // 需要代理的域名
ws: false, // 是否启用websockets
changeOrigin: true, //开启跨域
pathRewrite: {
//重写请求路径上匹配到的字段,如果不需要在请求路径上,重写为""
"^/api": "",
}
},
},
}
以上配置中,我配置了一个 /api,只有包含这个请求的路径才会走代理,例如:
http://localhost:8080/api/login //这个就可以走代理
http://localhost:8080/login //这个就不行
可以看到,要想所有的请求都进入代理中,就必须包含/api这个路径,那么可以对axios进行二次封装,给所有的请求加这个前缀,代码如下:
const requests = axios.create({
baseURL:'/api', // 设置通用请求的地址前缀
timeout:10000 //请求超时的时间
});
export default requests //将requests实例,对外进行暴露
发送请求可以写为:
requests.get('/login').then((response) => {
})
requests.get('/getlist').then((response) => {
})
requests.get('/user/hello').then((response) => {
})
此时发送的请求就是:
http://localhost:8080/api/login
http://localhost:8080/api/getlist
http://localhost:8080/api/user/hello
通过代理的target属性加工之后就是:
http://www.aaabbbccc.com/api/login
http://www.aaabbbccc.com/api/getlist
http://www.aaabbbccc.com/api/user/hello
就是把/api 之前的路径修改成了target里配置的目标服务器的路径。
在通过pathRewrite属性将/api 替换为空为:
http://www.aaabbbccc.com/login
http://www.aaabbbccc.com/getlist
http://www.aaabbbccc.com/user/hello
这样就可以访问到后端的对应接口了。