❤️弱水三千,只取一瓢饮❤️
🤞你好啊,我是小酥肉,欢迎阅读本博客👌
跨域相关知识:
- mvc模式
- sevlet容器
- 跨域相关知识点
本文专注于后端如何处理跨域
注意:我使用的springboot版本为2.7.x,servelt容器为tomcat 9.0.95
http请求在到达spring发生了什么
1)浏览器向后端发起一个http请求
2)tomcat用socket监听接收,并用io流将http请求转换为Servelt(封装Servelt)
3)Servlet容器管理该Servlet,并交付给spring MVC
4)spring MVC用dispatchServelt将该Servlet转发到对应的Controller,执行业务逻辑
5)返回响应,原路返回。(这里省略了response)
所以处理跨域就有了不同颗粒度/作用域
常见方案
下面是几种常见的跨域处理方案(后端)(分别对应图中1234):
添加过滤器 filter
在Servelt容器层添加filter,这一步可以在请求刚经过socket,来到容器时处理跨域。
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "36000000");
// response.setHeader("Access-Control-Allow-Headers", "content-type,Authorization");
response.setHeader("Access-Control-Allow-Credentials", "true");
filterChain.doFilter(servletRequest, servletResponse);
}
}
特点:servlet刚进入容器时进行跨域处理,由servelt容器(如tomcat)掌控
webMvcConfigure全局配置
当请求到达spring mvc后,我们可以通过一个配置类进行cors相关的配置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 覆盖所有请求
registry.addMapping("/**")
// 允许发送 Cookie
.allowCredentials(true)
// 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突)
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("*");
}
}
特点:细化到mvc框架,应用程序级别的配置,更适合java宝宝体质
添加拦截器Incerpeter
当然我们可以对dispatchServelt转发到controller之间加一层拦截器,它将对应路径(由你配置)的请求拦截,并提供preHanlder对其操作
// 设置跨域拦截器
@Component
public class YourInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "86400");
response.setHeader("Access-Control-Allow-Headers", "*");
// 如果是OPTIONS则结束请求(预检)
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
response.setStatus(HttpStatus.NO_CONTENT.value());
return false;
}
return true;
}
}
然后把YourInterceptor添加一些匹配路径
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private YourInterceptor yourInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 跨域拦截器需放在最上面
registry.addInterceptor(yourInterceptor).addPathPatterns("/**");
// 校验token的拦截器
//todo 添加其他的拦截器
//registry.addInterceptor(yourInterceptor).addPathPatterns("/admin/**");
}
}
特点:配合WebMvcConfigure全局配置灵活配置,并且由mvc框架掌控
由mvc框架掌控意味着:可以在WebMvcConfigure配置中引入IOC容器的bean。比如上面的@Resource
filter则不行,因为Servelt容器层的东西无法引入bean(跨应用)
@CrossOrigin注解
下面是CrossOrigin的源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin
该注解直接注解在方法/类上,可以给某个controller,甚至给某个restful 端点加来实现跨域,但一般跨域属于应用级别操作,这样也可以实现
总结
- 当请求违反了浏览器同源策略,会印发跨域
- 解决跨域的方式就是添加对应请求头(由cors标准规定的请求头),一般是后端处理
- 可以在servelt容器层处理跨域(filter)
- 也可以在spring mvc层处理跨域(WebMvcConfigure全局配置,拦截器,@CrossOrigin),可以根据自己的需求确定颗粒度
- filter不可以用bean,而mvc框架的配置则可以(WebMvcConfigure)
注意:跨域的方式还有很多。
比如网关层:cloud gataway,nginx
前端iframe配置,代理跨域
这里的解决方案就是java开发者应该怎么做
❤️弱水三千,只取一瓢饮❤️
🤞我是小酥肉 ,喜欢简单 ,期待您的留言👌