
java跨域配置失效,问题解决
在使用拦截器时,不能使用WebMvcConfigurer跨域配置,拦截器会让跨域配置失效(除非这个请求不会被拦截):在下层服务不需要在做任何跨域配置,例如注解@CrossOrigin,否则会由于配置冲突导致依然出现跨域问题。最后提一嘴,前端不建议做跨域处理,线上环境容易失效。然后我们再来看看,过滤器和拦截器执行的先后顺序。实现方法级别的细粒度(类/方法)的跨域控制。
·
在最近一次项目代码迁移到其他项目中时,需要对新迁移的项目模块配置跨域,于是我按照以往的方式处理,代码如下:
于是,在和前端联调的过程中,前端请求接口还是提示跨域,问题反馈如下:
于是找到了问题所在:
1.在使用拦截器时,不能使用WebMvcConfigurer跨域配置,拦截器会让跨域配置失效(除非这个请求不会被拦截)
2.在权限认证Filter认证失败时直接返回,导致没有经过拦截器,直接返回了。
然后我们再来看看,过滤器和拦截器执行的先后顺序
所以,我们应该把跨域 配置在过滤器上,代码如下:
@Component
public class CorsFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
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", "*");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
成功解决。
最后再来总结下通用后端解决跨域的方法:
1.@CrossOrigin 注解实现方法级别的细粒度(类/方法)的跨域控制
2.springboot2.0 实现WebMvcConfigurer 实现跨域
3.过滤器实现跨域
4.定制化参数实现跨域
@WebFilter(filterName = "corsFilter", urlPatterns = "/*",
initParams = {@WebInitParam(name = "allowOrigin", value = "*"),
@WebInitParam(name = "allowMethods", value = "GET,POST,PUT,DELETE,OPTIONS"),
@WebInitParam(name = "allowCredentials", value = "true"),
@WebInitParam(name = "allowHeaders", value = "Content-Type,X-Token")})
//前面要么是*,实际需求是根据业务参数定制化
public class CorsFilter implements Filter {
private String allowOrigin;
private String allowMethods;
private String allowCredentials;
private String allowHeaders;
private String exposeHeaders;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
allowOrigin = filterConfig.getInitParameter("allowOrigin");
allowMethods = filterConfig.getInitParameter("allowMethods");
allowCredentials = filterConfig.getInitParameter("allowCredentials");
allowHeaders = filterConfig.getInitParameter("allowHeaders");
exposeHeaders = filterConfig.getInitParameter("exposeHeaders");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (!StringUtils.isEmpty(allowOrigin)) {
if(allowOrigin.equals("*")){
// 设置哪个源可以访问
response.setHeader("Access-Control-Allow-Origin", allowOrigin);
}else{
List<String> allowOriginList = Arrays.asList(allowOrigin.split(","));
if (allowOriginList != null && allowOriginList.size() > 0) {
String currentOrigin = request.getHeader("Origin");
if (allowOriginList.contains(currentOrigin)) {
response.setHeader("Access-Control-Allow-Origin", currentOrigin);
}
}
}
}
if (!StringUtils.isEmpty(allowMethods)) {
//设置哪个方法可以访问
response.setHeader("Access-Control-Allow-Methods", allowMethods);
}
if (!StringUtils.isEmpty(allowCredentials)) {
// 允许携带cookie
response.setHeader("Access-Control-Allow-Credentials", allowCredentials);
}
if (!StringUtils.isEmpty(allowHeaders)) {
// 允许携带哪个头
response.setHeader("Access-Control-Allow-Headers", allowHeaders);
}
if (!StringUtils.isEmpty(exposeHeaders)) {
// 允许携带哪个头
response.setHeader("Access-Control-Expose-Headers", exposeHeaders);
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
5.使用SpringCloud网关GateWay实现跨域
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(Boolean.TRUE);//允许Cookie跨域
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");//不要设置成*,参考前面
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
注:在下层服务不需要在做任何跨域配置,例如注解@CrossOrigin,否则会由于配置冲突导致依然出现跨域问题
6、nginx配置代理解决跨域问题
server {
listen 8000;
server_name localhost;
# / 表示匹配路径为/的url
location / {
proxy_pass http://需要跨域的域名:5500;
}
# /user 表示访问以/user 开头 的地址 如/username,/user/find等
location /user {
proxy_pass http://需要跨域的域名:3000;
}
}
7、nginx配置响应头允许跨域
#
# Wide-open CORS config for nginx
#
location / {
#### 对OPTIONS请求,会设置很多的请求头,并返回204
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
最后提一嘴,前端不建议做跨域处理,线上环境容易失效
更多推荐
所有评论(0)