SpringBoot(Web)---跨域请求
1、跨域请求描述
跨域请求指的是发起request请求报文的协议或ip或port端口号与当前资源的协议或ip或port端口号不同,这种情况视作跨域请求。
2、跨域请求可能会出现的问题
- 浏览器发起跨域请求无法获取到目标资源。
- 实际请求报文与原本要发送的报文不同
3、跨域请求造成问题的原因
浏览器因相关规范,在发送跨域请求前,会在请求报文达到触发条件时发送请求方法为options的预检请求。当options预检请求能正常获取目标资源响应(携带若干允许访问请求头字段信息的响应报文),则表示目标资源端(服务器端)允许本次跨域请求,浏览器将正式发送实际请求;否则浏览器将发送url为/error请求到目标资源端(服务器端)获取对应错误请求的响应。
正常跨域访问请求流程图:
不正常跨域访问请求流程图:
4、options预检请求触发条件
主要有三种
- 请求方法使用了除GET、POST、HEAD外的PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH方法
- 自定义了非预置请求头字段
- 部分ContentType类型
5、如何处理跨域请求
5.1、通过处理器处理跨域请求
以下全局配置跨域处理与单HandlerMapping处理器配置跨域处理是使用了CorsProcessor
(默认情况下使用的是DefaultCorsProcessor
处理器)处理options预检请求与实际请求,作用为为各请求的响应头添加允许跨域请求的相关字段(如Access-Control-Allow-Origin
);
SpringBoot全局配置跨域处理:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //映射地址,/**表示所有映射地址
.allowedOrigins("*") //允许访问的ip地址,*表示所有ip地址
.allowedHeaders("*") //允许使用的请求头字段,*表示接受所有字段
.allowCredentials(true) //允许使用数字证书
.allowedMethods("GET", "POST", "DELETE", "PUT","PATCH") //允许访问的请求方法
.maxAge(3600); //表示预检请求响应时效为60分钟
}
}
通过注释对单处理器配置跨域处理:
@CrossOrigin(
origins = {"*"},
allowedHeaders = {"*"},
exposedHeaders = {"*"},
methods = {RequestMethod.GET},
allowCredentials = "true",
maxAge = 3600)
@GetMapping("/make")
public Account make(@RequestBody String str) {
}
5.2、通过过滤器处理跨域请求
配置过滤器处理跨域请求是全局有效的,虽然在请求流程上处理响应的时间可早于也可晚于5.1中使用的CorsProcessor处理器
,但效果都是一致的;都是处理options预检请求与实际请求,作用为响应头添加允许跨域请求的相关字段;
@Component
@Slf4j
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
5.3、通过拦截器处理跨域请求
允许跨域请求的关键在于响应头是否携带允许跨域请求的字段,故只要在拦截器中如过滤器一样向响应报文添加允许跨域请求的字段。