起因:
access-control-request-headers
的value前端代码展示:
后端获取request的header参数显示:
全是null
输出headers:
{sec-fetch-mode=cors, referer=http://localhost:8080/, sec-fetch-site=cross-site, accept-language=zh-CN,zh;q=0.9, origin=http://localhost:8080, access-control-request-method=POST, accept=*/*, host=127.0.0.1:8099, access-control-request-headers=content-type,headeruserid,headerusertoken, connection=keep-alive, accept-encoding=gzip, deflate, br, user-agent=Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36, sec-fetch-dest=empty}
变成了这样:access-control-request-headers=content-type,headeruserid,headerusertoken,
前端:
后端:
@CrossOrigin(origins = "*")
,进行了简单的跨域设置发现前端的参数key,浏览器的参数key和后端的参数key大小写不一致:
String userId = request.getHeader("headerUserId");
String userId2 = request.getHeader("HeaderUserId");
String userId3 = request.getHeader("Headeruserid");
尝试前端添加跨域:
尝试后端的拦截器内添加@CrossOrigin(origins = “*”)、具体拦截方法内给响应参数添加响应头:
重启前端项目、清除浏览器缓存、清除idea缓存、rebuild项目、重新运行:
试了很多方法,慢慢的就定位了问题:
@CrossOrigin(origins = "*")
加在我的接口上,但是拦截器先执行,如果没用通过那么直接返回,根本到不了我的接口,也就到不了我接口上的@CrossOrigin(origins = "*")
,那就没用跨域了// 支持跨域
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods",
"GET,POST,PUT,DELETE,OPTIONS");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
后面查询跨域的请求流程:
跨域请求的流程通常分为两个阶段:预检请求(Preflight Request)和实际请求。以下是跨域请求的一般流程:
预检请求阶段:
Access-Control-Request-Method
和Access-Control-Request-Headers
,用来询问服务器的允许范围。实际请求阶段:
下图展示了跨域请求的流程:
+-------------+ +-------------+
| Browser | | Server |
+-------------+ +-------------+
| |
| 1. 发送预检请求 |
+----------------------->|
| |
| 2. 接收预检响应 |
|<-----------------------+
| |
| 3. 发送实际请求 |
+----------------------->|
| |
| 4. 接收实际响应 |
|<-----------------------+
总的来说,跨域请求的流程就是浏览器先发送预检请求询问服务器是否允许跨域请求,然后根据服务器的响应决定是否发送实际请求。如果预检请求得到了服务器的允许,浏览器才会发送实际的请求。
跟着这个OPTIONS请求查找:
发现,只需要我把这个请求过滤掉即可,让它可以实际请求,使得我的自定义请求头 - 特定的请求头(access-control-request-headers=content-type,headeruserid,headerusertoken)可以接收到我就可以进行判断了。
if ("OPTIONS".equals(request.getMethod().toUpperCase())) {
return true;
}
有效果,解决了。
此处是使用的@CrossOrigin(origins = "*")
注解同时过滤掉OPTIONS
请求实现了跨域
还可以通过只设置一个跨域过滤器解决跨域问题:
下列方法转载于博客园作者小泉哥:
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;
/**
* 全局跨域配置类
* 跨域请求的配置,允许所有来源的跨域请求
*
* 跨域请求流程:
* 1. 浏览器发送预检请求(OPTIONS请求)给服务器,询问是否允许实际请求中包含特定的自定义请求头字段和请求方法。
* 2. 服务器根据预检请求的信息判断是否允许实际请求,发送适当的CORS响应头给浏览器。
* 3. 如果预检请求得到了服务器的允许,浏览器发送实际的请求给服务器。
* 4. 服务器收到实际请求后,处理请求并返回相应的响应给浏览器。
*
* 注:当设置allowCredentials为true时,Access-Control-Allow-Origin响应头不能使用通配符"*",而是必须明确指定允许的来源。
*
* @author red-velvet
* @since 2024/2/8
*/
@Configuration
public class GlobalCorsConfig {
/**
* 配置CorsFilter
* @return CorsFilter
*/
@Bean
public CorsFilter corsFilter() {
// 创建CorsConfiguration对象,配置CORS跨域规则
CorsConfiguration config = new CorsConfiguration();
// 允许所有来源的跨域请求
config.addAllowedOrigin("*");
// 允许携带凭据(例如Cookie)
config.setAllowCredentials(false);
// 允许所有请求方法的跨域请求
config.addAllowedMethod("*");
// 允许所有请求头的跨域请求
config.addAllowedHeader("*");
// 创建UrlBasedCorsConfigurationSource对象,注册CORS配置
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
// 创建CorsFilter对象,传入配置源
return new CorsFilter(configSource);
}
}
dCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
// 创建CorsFilter对象,传入配置源
return new CorsFilter(configSource);
}
}