springboot解决CORS跨域请求的三种方法
前段时间,由于公司的项目采用前后端分离开发,前端和后端部署在不同的服务器上,导致前段不能正常访问后端,原因是后端没有开放CORS跨域请求。
CORS跨域请求简介
1、js跨域请求:
只要协议、域名、端口有任何一个不同,都被当作是不同的域。
2、跨域调用测试:
前端控制台出现 以下信息,表示不能跨域访问:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9100' is therefore not allowed access. The response had HTTP status code 400.
3、跨域解决方案 CORS
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
请求过程如下图:
Preflight Request:
然后服务器端给我们返回一个Preflight Response
解决方案:
方案一:
使用spring 标签,注意spring的版本高于4.2
@CrossOrigin(origins="http://localhost:9105",allowCredentials="true")。
示例:
在Controller的方法上加上@CrossOrigin注解,
@CrossOrigin(origins = "*",allowCredentials ="true")
@GetMapping("/assetList")
public Result list(){
return new Result();
}
方案二:
通过继承WebMvcConfigurationSupport类,然后重写addCorsMappings方法,
示例:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedMethods("*")
.allowedOrigins("*")
.allowedHeaders("*");
}
}
方案三:
自定义过滤器filter,然后在filter中拦截cors请求,并设置响应头:
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String origin = request.getHeader("Origin");
if(!StringUtils.isEmpty(origin)){
//cors请求
System.out.println("cors请求");
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods","*");
response.setHeader("Access-Control-Allow-Headers","*");
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_ACCEPTED);
}
}
filterChain.doFilter(request,response);
}
}
在springboot中,我们可以通过org.springframework.web.filter.CorsFilter类来实现,
CorsFilter类需要CORS配置才能正常工作,CORS配置对应的类是org.springframework.web.cors.CorsConfigurationSource。
示例:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
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 org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 处理跨域请求
* @return
*/
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
补充:推荐使用Filter的方式处理跨域问题,比如全局异常处理器拦截到的异常信息返回前端时,如果需要跨域则“方案二”可能无效,使用下列代码即可解决问题:
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
本人水平有限,代码有不足之处还请大家见谅,欢迎大家提建议。本人目前主要方向是Java,如果有兴趣,可以一起交流,
Java成长交流学习群:184998348