由来
今天新开项目,用的之前的管理框架,springboot3.2+jdk17+vue2+elementui+axios,的时候,因为端口换了报错Access to XMLHttpRequest at ‘http://192.168.3.19:11111/user/info?personId=1’ from origin ‘http://192.168.3.19:22222’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute
分析
从报错信息来看是最常见的跨域问题,跨域的定义是请求发起网站的协议://ip:端口号,有一个地方和请求地址不一致,就会引起跨域,但是我后端是配置了跨域,代码如下
/**
* CORS配置源, 解决跨域
*
* @return {@link CorsConfigurationSource}
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许所有头部
corsConfiguration.setAllowedHeaders(List.of("*"));
// 允许所有方法
corsConfiguration.setAllowedMethods(List.of("*"));
corsConfiguration.setAllowedOrigins(List.of("*"));
// 设置预检请求的最大有效时间(秒)
corsConfiguration.setMaxAge(CORS_MAX_AGE);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
可以看到我设置了AllowedOrigins为*,按道理来说是可以允许所有请求访问的,但是为什么会报错呢?
原因
在查询了其他博客后,发现是前端axios配置的问题,代码如下
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
withCredentials: true, // send cookies when cross-domain requests
timeout: 5000, // request timeout
});
首先我们都知道,请求都是无状态的,在前期的单体应用中,要知道请求的页面是否登录,只能通过请求携带sessionId去查看服务端session中是否有登录信息,但是现在引入了中间件redis等,可以通过在heard中携带token去判断请求是否登录了,
在这代码中,前端为了让后端识别请求是否登录,会携带sessionId,通过设置withCredentials: true去让服务端返回sessionId并在后面的请求携带此sessionId, 但是现在都是使用springboot+redis+jwt 去解决登录状态的维持,所以前端的请求可以是无状态的。
解决
知道原因后就可以很简单的知道怎么去解决,将vue的axions的配置withCredentials: true设置为false就好了,如下
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
withCredentials: false, // send cookies when cross-domain requests
timeout: 5000, // request timeout
});
后端代码不需要动
拓展
当你需要后端返回sessionId该怎么设置。
也很简单,后端设置如下
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许所有头部
corsConfiguration.setAllowedHeaders(List.of("*"));
// 允许所有方法
corsConfiguration.setAllowedMethods(List.of("*"));
// 设置允许的源--搭配前端axios的withCredentials: true,
corsConfiguration.setAllowedOrigins(List.of("http://localhost:22222", "http://192.168.3.19:22222"));
// 明确允许凭据
corsConfiguration.setAllowCredentials(true);
// 设置预检请求的最大有效时间(秒)
corsConfiguration.setMaxAge(CORS_MAX_AGE);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
需要配置允许的请求头, corsConfiguration.setAllowedOrigins(List.of(“http://localhost:22222”, “http://192.168.3.19:22222”));和 corsConfiguration.setAllowCredentials(true);去告诉前端需要携带cookie去分辨你是否携带了sessionId
前端设置
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
withCredentials: true, // send cookies when cross-domain requests
timeout: 5000, // request timeout
});
去携带初次访问返回的sessionId