Vue跨域配置详解
前言
跨域这个词,对前端程序员来说,可谓是屡见不鲜。正好最近在做项目时,又遇到了跨域问题,无奈只能继续去网上查询资料来查看vue如何进行配置。为了方便,最终决定自力更生,自己总结一番,省的之后遇到跨域问题去网上各种查询,浪费时间。
首先对跨域做一个简单的回顾吧。
1、什么是跨域?
当一个请求url的
协议
、域名
、端口
三者之间任意一个与当前页面url不同即为跨域。比如
http://www.test.com/
这个url,http
是协议,www.test.com
是域名,80
是端口。(默认端口:http端口80、https端口443、tomcat端口8080
)
当前页面url | 请求页面url | 是否跨域 | 原因 |
---|---|---|---|
http://www.test.com/ | http://www.test.com/index.html | 否 | 协议、域名、端口都相同,只是请求内容不同 |
http://www.test.com/ | https://www.test.com/ | 是 | 协议不同,前者是hhtp,后者是https |
http://www.test.com/ | http://www.test2.com/ | 是 | 域名不同,前者是test,后者是test2 |
http://www.test.com:8080/ | http://www.test.com:8002/ | 是 | 端口不同,前者是8080,后者是8002 |
2、为什么会出现跨域?
我们可以先假设,如果浏览器没有安全策略的话。Web
世界会是变成什么样子?
这里假设有A
网站,如果没有相关的安全策略,Web
世界就是开放的。那么任何资源都可以接入A
网站,如视频、音频、图片、可执行脚本等。但这样会造成无序或者混沌的局面,出现很多不可控的问题。
比如A
网站请求到了一个恶意网站(B
)的恶意脚本,就可以修改A
网站的DOM、CSSOM结构,还可以插入一段JavaScript脚本,甚至可以获取A
网站的用户名和密码及Cookie信息。
因此,我们就需要一种安全策略来保障我们的隐私和数据的安全,这就引出了页面中最基础、最核心的安全策略:同源策略
(Same-origin policy
),它是浏览器最核心也是最基本的安全功能。
什么是同源策略呢?
协议、域名和端口都相同,那么这两个url
就是同源的。如果两个url
协议、域名、端口任意一个不相同,则这两个url
就是不同源的,他们的请求就算是跨域
3、vue中配置跨域
1、首先用express模拟开一个服务
代码语言:javascript复制// 创建应用对象
const express = require('express');
// 创建应用对象
const app = express();
// 创建路由规则
app.get('/data',(request,response) => {
let obj = {
name:'test',
age:18
}
response.send(obj);
});
// 监听端口启动服务
app.listen(8002,() => {
console.log("服务已启动,82端口监听中...");
})
服务已经开好,准备前端发请求了。
2、创建一个vue项目,前端代码如下:
代码语言:javascript复制# 写一个特简单的页面,只放一个按钮,用来发请求。
<template>
<div>
<el-button @click="getData">获取内容</el-button>
</div>
</template>
<script>
import axios from "axios"
export default {
nema:'Current',
data(){
return{
data : null
}
},
methods:{
getData(){
axios.get("http://localhost:82/data").then(res=>{
console.log(`请求内容为${res.data}`);
},
error=>{
console.log(`请求错误`);
})
}
}
};
</script>
<style scoped>
</style>
点击获取内容按钮,不出所料,报了跨域问题。如下图所示:
Access to XMLHttpRequest at 'http://localhost:8002/data' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Main.vue?48a8:21 请求错误
大概意思可以这样描述:我的vue服务在localhost的8080
端口,express的服务在8002
端口。因为端口不同,所以同源策略会生效。因此8080
端口请求不到8002
端口的内容。
关于跨域,需要明白的一点是。这个请求后端是可以接收到的,并不是说跨域了,请求发都发不出去。并且服务端可以将数据返回给浏览器,浏览器也可以正常接收数据,但是因为同源策略,浏览器没有进一步传递数据,浏览器将数据拦截了。
3、解决思想
配置代理服务器
正常的请求流程如下,前端直接向后端发起请求。因为端口不同,所以会触发同源策略,报跨域错误,浏览器不显示数据。
配置代理服务器之后,流程就变为:前端不再向后端发起数据请求,而是向代理服务器发请求,代理服务器收到请求之后,它会向后端发起请求,后端返回数据给代理服务器。因为前端和代理服务器之间是同源,因此前端可以直接获取到代理服务器的内容。这样前端就可以获取到后端返回的数据了,不会再报跨域问题。说白了就是代理服务器欺骗了浏览器,让浏览器以为没有跨域。
这里可能会有人问,粉色的代理服务器端口(8080
)和后端(82
)也是不一样的啊,他们不会报跨域错误吗?答案是不会的,跨域只是浏览器的一种安全策略,代理服务器它是一个服务器,服务器与服务器之间通信没有跨域这个问题的,也就是说跨域这个问题只存在于浏览器。
关于两个8080
端口问题,浏览器是访问8080
端口,而不是占用端口,8080
上只有一个代理服务器在监听。
4、配置跨域,解决问题。
4.1、配置代理一
在vue.config.js中配置devServer
,详细配置如下:
module.exports = {
pages:{
index:{
entry:"src/main.js"
}
},
// 关闭语法检查
lintOnSave:false,
// 配置跨域
devServer:{
proxy: 'http://localhost:8002'
}
}
代码语言:javascript复制组件代码如下,注意,我们请求的地址不再是
http://localhost:8002/data
,而是http://localhost:8080/data
。因为我们请求的是代理服务器,我们是通过代理服务器去后端请求数据,因此这里注意,请求地址中端口一定要改成8080
。
<template>
<div class="hello">
<el-button @click="getData">获取内容</el-button>
</div>
</template>
<script>
import axios from "axios"
export default {
nema:'Current',
data(){
return{
data : null
}
},
methods:{
getData(){
axios.get("http://localhost:8080/data").then(res=>{
console.log("请求内容为",res.data);
},
err=>{
console.log("请求错误",);
})
}
}
};
</script>
运行实例:
可以看到,请求成功,不再报跨域错误,成功取到{ name:'test', age:18 }
。
注意,代理服务器收到的任何请求并不是都会转发出去的,如果服务器自身有相关资源,则不会转发请求,而是直接返回相关资源。如何理解呢?就是说,如果这个代理服务器有一个
test
数据(不管它是什么文件类型的),你正好请求的也是test
数据,它就不会将你的请求转发出去,而是直接将其自身有的test
数据给你返回去。来验证一下。
首先将组件中请求路径改为"http://localhost:8080/test"
<template>
<div class="hello">
<el-button @click="getData">获取内容</el-button>
</div>
</template>
<script>
import axios from "axios"
export default {
nema:'Current',
data(){
return{
data : null
}
},
methods:{
getData(){
axios.get("http://localhost:8080/test").then(res=>{
console.log("请求内容为",res.data);
},
err=>{
console.log("请求错误",);
})
}
}
};
</script>
之后在public
目录下添加一个test
文件,并写入如下内容{ "name":"test2", "msg":"本地数据" }
运行实例:
这是需要注意的一个点
以上方式配置代理有如下两个缺点:
- 只能配置一个代理,不能配置多个代理。
- 无法灵活控制请求是否走代理。
4.2 配置代理二
为了解决方式一配置方式存在的问题,我们需要进一步了解新的代理配置方式。参考Vue官方代理配置方案。
因此,我们的配置方式可以改为:
代码语言:javascript复制module.exports = {
pages:{
index:{
entry:"src/main.js"
}
},
// 关闭语法检查
lintOnSave:false,
devServer:{
proxy: {
//匹配前缀,也就是说只有当请求的前缀是/api,才让代理去转发该请求,如果不是/api,则代理不进行转发。
"/api":{
target:"http://localhost:8002",
// 必须有pathRewrite属性,否则代理转发的请求路径中会包含/api,会出现404错误。必须将/api再转化成空字符串
pathRewrite:{"^/api":""},
// 支持websocket
ws: true,
// 控制请求头中的host值
changeOrigin:false
}
}
}
}
代码语言:javascript复制组件代码如下:我们在请求路径中添加了请求前缀
/api
。当代理服务器识别到有/api
这个请求前缀,虽然本地也有test文件,但是代理服务器依旧会将这个请求发出。
<template>
<div class="hello">
<el-button @click="getData">获取内容</el-button>
</div>
</template>
<script>
import axios from "axios"
export default {
nema:'Current',
data(){
return{
data : null
}
},
methods:{
getData(){
axios.get("http://localhost:8080/api/test").then(res=>{
console.log("请求内容为",res.data);
},
err=>{
console.log("请求错误",);
})
}
}
};
</script>
代码语言:javascript复制// 创建应用对象
const express = require('express');
// 创建应用对象
const app = express();
// 创建路由规则
app.get('/data',(request,response) => {
console.log("访问data请求");
let obj = {
name:'test',
age:18
}
response.send(obj);
});
app.get('/test',(request,response) => {
console.log("访问test请求");
let obj = {
name:'test',
age:20
}
response.send(obj);
});
// 监听端口启动服务
app.listen(8002,() => {
console.log("服务已启动,8002端口监听中...");
})
运行实例如下:获得到服务端的数据
{ name:'test', age:20 }
,而不是本地的{ "name":"test2", "msg":"本地数据" }
解决配置多个代理这一问题,只需在proxy
属性中再添加一个配置即可。
module.exports = {
pages:{
index:{
entry:"src/main.js"
}
},
// 关闭语法检查
lintOnSave:false,
devServer:{
proxy: {
//匹配前缀
"/api":{
target:"http://localhost:8002",
pathRewrite:{"^/api":""},
// 支持websocket
ws:true,
changeOrigin:false
},
// 在8002的基础上,再增加一个8003端口的代理
"/newapi":{
target:"http://localhost:8003",
pathRewrite:{"^/newapi":""},
// 支持websocket
ws:true,
changeOrigin:false
}
}
}
}
代码语言:javascript复制这边开
8002
、8003
两个服务器
//8002服务器
// 创建应用对象
const express = require('express');
// 创建应用对象
const app = express();
// 创建路由规则
app.get('/test',(request,response) => {
console.log("访问test请求");
let obj = {
name:'test',
msg:"8002端口信息"
}
response.send(obj);
});
// 监听端口启动服务
app.listen(8002,() => {
console.log("服务已启动,8002端口监听中...");
})
代码语言:javascript复制// 8003服务器
// 创建应用对象
const express = require('express');
// 创建应用对象
const app = express();
// 创建路由规则
app.get('/test',(request,response) => {
console.log("访问test请求");
let obj = {
name:'test',
msg:"8003端口信息"
}
response.send(obj);
});
// 监听端口启动服务
app.listen(8003,() => {
console.log("服务已启动,8003端口监听中...");
})
代码语言:javascript复制组件代码,新增了一个端口号为8003的数据请求。
template>
<div class="hello">
<el-button @click="getData">获取内容</el-button>
<el-button @click="getData2">获取内容2</el-button>
</div>
</template>
<script>
import axios from "axios"
export default {
nema:'Current',
data(){
return{
data : null
}
},
methods:{
getData(){
axios.get("http://localhost:8080/api/test").then(res=>{
console.log("请求内容为",res.data);
},
err=>{
console.log("请求错误",);
})
},
getData2(){
axios.get("http://localhost:8080/newapi/test").then(res=>{
console.log("请求内容为",res.data);
},
err=>{
console.log("请求错误",);
})
}
}
};
</script>
运行实例,成功获取
8002
、8003
端口数据,成功配置多个代理。
5、附-服务端跨域配置
当然,我们也可以直接在后端服务器做相应配置,这里就以express
为例:
// 配置关键代码Access-Control-Allow-Origin与Access-Control-Allow-Methods
app.use((req,res,next)=>{
//实验验证,只需要设置这一个就可以进行get请求
res.header('Access-Control-Allow-Origin', 'http://localhost:8080')//配置8080端口跨域
//res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, OPTIONS') // 允许的 http 请求的方法
// res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With')
next()
})
Access-Control-Allow-Origin
:设定请求源,就告诉了浏览器。如果请求我的资源的页面是我这个响应头里记录了的"源",则不要拦截此响应,允许数据通行。如上配置,由于服务端设置了res.header('Access-Control-Allow-Origin', 'http://localhost:8080')
,如果请求数据的源是http://localhost:8080
则可以允许访问返回的数据。这样浏览器就不会抛出错误提示,而是正确的将数据交给你。Access-Control-Allow-Methods
:允许请求的方法。Access-Control-Allow-Headers
:用于preflight request
(预检请求)中,列出了将会在正式请求的Access-Control-Expose-Headers
字段中出现的首部信息。
4、总结
以上就是关于跨域及Vue
配置跨域的基本内容。首先介绍了什么是跨域?为什么会出现跨域?接着重点介绍了Vue
中如何配置跨域。最后还提供了服务端(express
)的跨域配置。