SpringBoot解决跨域问题
2022.8.24,时隔两年多,对跨域有了更近一步的认知,原先的解决方案越发觉得过于粗暴,果然前段时间出了问题。
基于springboot的全局跨域配置策略是加过滤器,但是很多时候,我们并不会自己撸一个过滤器,而是会去实现mvc的拦截器做跨域处理。
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer
{
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("*")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}
上面的代码乍一看没什么问题,某些情况下是能起到跨域处理的效果。
但是,我最近接手一个项目的时候,需要在这个项目中加上用户认证的拦截器,就发现了问题,而且是大问题!
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
//注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor).addPathPatterns("/**")
.excludePathPatterns("/sys/login")
.excludePathPatterns("/error", "/csrf")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
}
原来的代码就是上面两个配置写到一起了,这个时候你就会发现,你所有的请求,都是跨域的!
奇了怪了,明明配了啊,为什么还会跨域呢?这个必须要读一读源码才能知道!等有时间了再回来记录问题的根本原因,这边先记录解决方案!
解决方案就是:
- 跨域配置使用下面原来文章中贴的的过滤器,
- 用户认证的拦截器使用上面贴的烂机器代码。
因为过滤器会在拦截器之前被触发,所以跨域的问题解决了!(撒花!!!)
以下是原文章(2020.4.9)
接触Java的时间并不是很长,我一直以为跨域是前端需要解决的问题。直到有一天,一个前端的技术经理跟我说cityMaker无法处理跨域问题的时候,我才意识到跨域问题的严重性。因此有了这篇文章。
跨域
在说明跨域之前,我还是希望能把问题由来还原,以加深对这次过程的印象。
这次的后端接口不多,就几个统计数据的接口,前端使用cityMaker做的大屏端展示数据(美名曰“驾驶仓”)。由于驾驶仓部署在其他远程服务器上,而后端接口在另外一台服务器,所以就出现了跨域问题。(这个原因是前端的技术经理跟我说的,我没有权限接触驾驶仓的服务器,所以就按照这个原因算吧!)
跨域
跨域通常指的是浏览器对javascript的同源策略的限制。
比如我碰到的问题就是浏览器相当于cityMaker,而后端服务相当于脚本,浏览器出于安全考虑,是无法得到我的后端服务数据的。
用几个例子展示可能会有更加清晰的认识:
例子中均为 index.html 调用 hello 服务。
上述情况非跨域。
上述情况跨域,因为图中的主域名不一样。
上述情况跨域,因为图中的子主域名不一样。
上述情况跨域,因为图中的端口不一样,hello默认使用ng的80端口代理。
上述情况跨域,因为图中的协议不一样。
思考
看到这里需要有一个疑问,当我们在本地调试的时候,用127.0.0.1调用localhost会跨域吗?
SpringBoot中解决跨域
SpringBoot中解决跨域我一般采用两种办法。
- 利用SpringBoot自己原生的跨域策略,在Controller上添加注解 @CrossOrigin
@CrossOrigin的更多用法需要自行搜索。
需要的同学可以参考博客园大佬 淼淼之森 的文章:注解@CrossOrigin解决跨域问题
- 自己写一个过滤器,放行跨域请求,过滤器的规则可以视项目情况做修改。
@Component
public class SimpleCORSFilter 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, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600"); //设置过期时间
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, Authorization, access_token");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}