【前后端分离】跨域问题

问题

VUE前端项目和SpringBoot后端项目起起来后,发现前端无法访问后台地址。报错如下:

1
Access to XMLHttpRequest at 'http://localhost:9000/test' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

前端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
// 添加全局样式
import './assets/css/global.css'
// 引入iconfont
import './assets/font/iconfont.css'
// 导入axios
import axios from 'axios'
// 挂载axios
Vue.prototype.$http = axios
// 设置访问路径(后端地址)
axios.defaults.baseURL = "http://localhost:9000/"

Vue.config.productionTip = false

new Vue({
router,
render: h => h(App)
}).$mount('#app')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<template>
<div class="login_container">
<div class="login_box">
<!-- 头像 -->
<div class="avatar_box">
<img src="../assets/logo.png" />
</div>
<!-- 登陆表单 -->
<el-form ref="loginFormRef" :rules="loginRules" :model="loginForm" class="login_form" label-width="0">
<el-form-item prop="username">
<el-input v-model="loginForm.username" prefix-icon="iconfont icon-usercenter"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" prefix-icon="iconfont icon-unlock" type="password"></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button type="primary" @click="login()">提交</el-button>
<el-button type="info" @click="resetLoginForm()">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 表单数据
loginForm: {
username: "admin",
password: "123456"
},
// 表单校验
loginRules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 5, max: 12, message: '长度在 5 到 12 个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 10, message: '长度在 6 到 10 个字符', trigger: 'blur' }
],
},
}
},
methods: {
resetLoginForm() {
this.$refs.loginFormRef.resetFields();
},
login() {
this.$refs.loginFormRef.validate(async valid => {
if(!valid) {
return;
}
const {data: res} = await this.$http.post("test");
console.log(res);
})
}
}
}
</script>
<style lang="less" scoped>
.login_container {
background-color: #2b4b6b;
height: 100%;

}
.login_box {
width: 450px;
height: 300px;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
.avatar_box {
width: 130px;
height: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 5px;
box-shadow: 0 0 10px #ddd;
position: absolute;
left: 50%;
transform: translate(-50%,-50%);
background-color: #eee;
img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
}
}
.btns {
display: flex;
justify-content: flex-end;
}
.login_form {
position: absolute;
bottom: 0%;
width: 100%;
padding: 0 10px;
box-sizing: border-box;
}
</style>

后端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.sport.util;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
* @author chenhy
* @date 2021/5/6
*/

/**
* 全局配置类--配置跨域请求
*/
@Configuration
public class Webconfig extends WebMvcConfigurerAdapter {
/**
* 1.域访问路径
* 2.请求来源
* 3.方法
* 4.允许携带token等信息
* 5.设置生命周期
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080/", "null")
.allowedMethods("GET", "POST", "PUT", "OPTION", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.example.sport.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author chenhy
* @date 2021/5/6
*/
@RestController
public class LoginController {

@RequestMapping("/test")
public String test() {
return "测试成功!";
}
}

原因查找

根据报错,很明显是跨域问题。那么到底在哪里出错了?前端还是后端?

  • 一开始以为是浏览器的问题,从edge转到谷歌浏览器后,问题仍然存在。
  • 查看了前端的axios挂载以及请求的情况,请求路径没有问题。
  • 那么就是后端的问题了。
    我尝试着按照网上的博客来修改Webconfig .java文件,但是没有用(自己太垃圾,没改对而已)。
    然后,我尝试着将跨域的注解直接放到方法上面:
    1
    @CrossOrigin(origins = "http://localhost:8080", maxAge = 3600)
    重启后,项目竟然可以正常访问了!!!
    这个时候,我再回看之前的跨域配置文件Webconfig .java,发现竟然是url在最后多出一条斜杠的原因。
    需要将
    1
    .allowedOrigins("http://localhost:8080/", "null")
    修改为
    1
    .allowedOrigins("http://localhost:8080", "null")