SpringBoot与Vue项目的跨域问题
1. 项目初始化
1.1 SpringBoot项目
package com.icebear.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author icebear
* @date 2023/2/17
* @info 测试sessionID
*/
@RestController
@RequestMapping("/api/tests")
public class TestController {
@GetMapping("/getSession")
public String getSession(HttpServletRequest request, HttpServletResponse response) {
return request.getSession().getId();
}
}
1.2 Vue项目
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import axios from "axios";
axios.defaults.baseURL = 'http://localhost:8080/api'
const app = createApp(App)
app.mount('#app')
app.config.globalProperties.$axios = axios
<!-- App.vue -->
<template>
<div class="btn-div">
<button @click="send">发送请求,获取sessionId</button>
</div>
<div class="text-div">
后面显示获取的sessionId:
<span v-text="sessionId" style="color: red"></span>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
sessionId: ''
}
},
methods: {
send() {
this.$axios.get('/tests/getSession')
.then(res => {
console.log(res)
this.sessionId = res.data
})
.catch(err => {
console.log(err)
})
}
}
}
</script>
<style scoped>
</style>
2. 跨域问题及解决
2.1 跨域问题出现
在启动SpringBoot项目和Vue项目之后,点击浏览器页面内的按钮,发送请求,此时浏览器的控制台会出现如下错误:
2.2 SpringBoot解决跨域问题
2.2.1 使用@CrossOrigin注解
package com.icebear.controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author icebear
* @date 2023/2/17
* @info 测试sessionID
*/
@RestController
@RequestMapping("/api/tests")
// 使用@CrossOrigin注解处理跨域问题
@CrossOrigin
public class TestController {
@GetMapping("/getSession")
public String getSession(HttpServletRequest request, HttpServletResponse response) {
return request.getSession().getId();
}
}
浏览器结果如下:
2.2.2 实现WebMvcConfigurer接口的addCorsMappings方法
package com.icebear.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
*
* @author icebear
* @date 2023/2/17
* @info 方法二:实现WebMvcConfigurer的addCorsMappings方法处理跨域
*/
@Configuration
public class MyCrosConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
.allowCredentials(true) // 是否发送cookie
.allowedOriginPatterns("*") // 支持域
.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法
.allowedHeaders("*")
.exposedHeaders("*");
}
}
浏览器结果如下:
2.2.3 添加CorsFilter
package com.icebear.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
/**
*
* @author icebear
* @date 2023/2/17
* @info 方法三:添加CorsFilter解决跨域问题
*/
@Configuration
public class MyCorsFilter {
@Bean // 不要忘记添加此注解
public CorsFilter corsFilter() {
// 创建CORS配置对象
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*"); // 设置支持域
config.setAllowCredentials(true); // 是否发送cookie
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); // 支持的请求方式
config.addAllowedHeader("*"); // 允许的原始请求头部信息
config.addExposedHeader("*"); // 暴露的头部信息
// 添加地址映射
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", config);
// 返回CorsFilter对象
return new CorsFilter(corsConfigurationSource);
}
}
浏览器结果如下:
3. 服务器部署后没有Cookie
3.1 环境模拟
3.1.1 软件准备
- linux虚拟机
- 安装java运行环境
- 安装nginx:LINUX安装nginx详细步骤
3.1.2 部署项目
- Vue项目构建成功后上传虚拟机;
- SpringBoot项目打包成功后上传虚拟机;
3.1.3 模拟域名
- 使用命令
ifconfig
获取虚拟机ip地址,例如:192.168.1.3
; - 修改windows的hosts文件,将域名和虚拟机的ip地址做映射;
- 修改nginx配置,指定域名对应的端口和项目位置;
http {
......
# 二级域名转发
server {
listen 80;
server_name bear.iceindex.xyz;
# root /www/iceindex.xyz/dist;
# 二级域名对应的Vue项目转发
location / {
proxy_pass http://0.0.0.0:8091;
}
}
# Vue项目的实际访问地址
server {
listen 8091;
server_name localhost;
root /www/iceindex.xyz/dist;
location / {
root /www/iceindex.xyz/dist;
try_files $uri $uri/ /index.html;
}
}
}
3.2 运行项目
3.2.1 前后端部署在同一台服务器中
3.2.1.1 通过IP:Port方式访问项目
浏览器输入Vue
项目的IP:Port
访问,并发送请求,结果如下:
解决方法:
修改axios
的默认配置:
import { createApp } from 'vue'
import App from './App.vue'
import axios from "axios";
// 本地SpringBoot项目地址
// axios.defaults.baseURL = 'http://localhost:8080/api'
// 服务器SpringBoot项目地址
axios.defaults.baseURL = 'http://192.168.1.3:8080/api'
// 添加下面一行可以获取cookie
axios.defaults.withCredentials = true
const app = createApp(App)
app.mount('#app')
app.config.globalProperties.$axios = axios
修改后结果:
从下图的结果中可以看出,成功获得了JSESSIONID所对应的cookie
3.2.1.2 通过域名访问项目
在浏览器输入Vue
项目配置的域名地址进行访问,并发送请求,结果如下:
从下图中的结果中可以看出,没有获得JSESSIONID所对应的cookie
解决方法:
- 修改
axios
的baseUrl
配置:
import { createApp } from 'vue'
import App from './App.vue'
import axios from "axios";
// 本地SpringBoot项目地址
// axios.defaults.baseURL = 'http://localhost:8080/api'
// 服务器SpringBoot项目地址 IP对应
// axios.defaults.baseURL = 'http://192.168.1.3:8080/api'
// 服务器SpringBoot项目地址 域名对应
axios.defaults.baseURL = 'http://bear.iceindex.xyz/api'
// 添加下面一行可以获取cookie
axios.defaults.withCredentials = true
const app = createApp(App)
app.mount('#app')
app.config.globalProperties.$axios = axios
- 修改
nginx
配置:
{
# 二级域名转发
server {
listen 80;
server_name bear.iceindex.xyz;
# root /www/iceindex.xyz/dist;
# 二级域名对应的Vue项目转发
location / {
proxy_pass http://0.0.0.0:8091;
}
# 二级域名对应的SpringBoot项目转发
location /api {
proxy_pass http://0.0.0.0:8080;
}
}
# Vue项目的实际访问地址
server {
listen 8091;
server_name localhost;
root /www/iceindex.xyz/dist;
location / {
root /www/iceindex.xyz/dist;
try_files $uri $uri/ /index.html;
}
}
}
修改后的结果:
3.2.2 前后端部署在不同服务器中
由于前后端部署在不同的服务器中,Vue项目的地址和SpringBoot项目的地址是不同的,模拟的方式为:Vue项目中的axios的baseUrl设置为SpringBoot项目地址:
import { createApp } from 'vue'
import App from './App.vue'
import axios from "axios";
// 本地SpringBoot项目地址
// axios.defaults.baseURL = 'http://localhost:8080/api'
// 服务器SpringBoot项目地址 IP对应
// axios.defaults.baseURL = 'http://192.168.1.3:8080/api'
// 服务器SpringBoot项目地址 域名对应
axios.defaults.baseURL = 'http://bear.iceindex.xyz/api'
// 添加下面一行可以获取cookie
axios.defaults.withCredentials = true
const app = createApp(App)
app.mount('#app')
app.config.globalProperties.$axios = axios
本地运行Vue项目结果:
解决方法:
将协议升级为https
,并设置Cookie的SameSite值为None,Secure值改为true
详情参考:【跨域】一篇文章彻底解决跨域设置cookie问题!
4. 其他参考
解决vue+springboot前后端分离项目,前端跨域访问sessionID不一致导致的session为null问题
版权声明:本文为ice_bear221原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。