Spring MVC中处理CORS跨域有如下几种方式
- @CrossOrigin(注解)
- CorsRegistry(全局配置)
- SpringMVC拦截器
- 实现Filter接口
编写test.html文件如下:当然JQuery或直接AJAX请求也可以
Title
点击下载axios.min.js文件
编写测试Controllerpackage com.yyoo.springmvc.controller; import com.yyoo.springmvc.bean.MyResponse; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("demo6") public class Demo6Controller { @RequestMapping("checkCors") public MyResponse checkCors(){ return MyResponse.success("CORS请求成功!"); } }测试请求
@CrossOrigin(注解)解决跨域如图,我们在没有进行任何的跨域处理时,点击CORS请求按钮后会有两个请求发送,而且都有错误,而且它们的状态也不一样。第一个就是“预检”请求,第二个才是实际的请求。关于请求的状态以及相关的http知识不是我们本章的讨论内容。接下来我们来通过以上几种方式来处理跨域问题。
package com.yyoo.springmvc.controller; import com.yyoo.springmvc.bean.MyResponse; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("demo6") public class Demo6Controller { @RequestMapping("checkCors") @CrossOrigin public MyResponse checkCors(){ return MyResponse.success("CORS请求成功!"); } }
可见@CrossOrigin注解方式十分简单,在对应的方法上加上该注解即可。@CrossOrigin注解也可以作用在类上,让该类下的请求方法都支持跨域。
@CrossOrigin注解也可以设置对应的参数,直接查看源码即可了解。
package org.springframework.web.bind.annotation; import java.lang.annotation.documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.List; import org.springframework.core.annotation.AliasFor; import org.springframework.web.cors.CorsConfiguration; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @documented public @interface CrossOrigin { @AliasFor("origins") String[] value() default {}; @AliasFor("value") String[] origins() default {}; String[] originPatterns() default {}; String[] allowedHeaders() default {}; String[] exposedHeaders() default {}; RequestMethod[] methods() default {}; String allowCredentials() default ""; long maxAge() default -1; }CorsRegistry(全局配置)解决跨域
@CrossOrigin注解方式简单,但如果我们需要为我们的应用设置一个全局的CORS配置,@CrossOrigin就不太方便了。这时候我们可以通过CorsRegistry来配置
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/demo6/**") .allowedOrigins("*") .allowedMethods("GET", "OPTIONS","POST") .allowCredentials(false).maxAge(3600); // 还能添加更多的 mappings... } }
SpringMVC 拦截器解决跨域WebMvcConfigurer:我们添加的大部分配置都用到了它,目前为止我们用他添加过类型转换器、拦截器、以及现在的CORS全局配置。
package com.yyoo.springmvc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.addHeader("Access-Control-Allow-Origin", "*"); // 允许请求携带cookie response.setHeader("Access-Control-Allow-Credentials", "false"); response.addHeader("Access-Control-Max-Age","86400"); // 响应类型 response.addHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS"); // 响应头设置 response.addHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With, X-authentication, X-client, X-Token, X_Requested_With"); return true; } }
此方式在我们需要携带cookie的时候比较有用,因为携带cookie的时候需要Access-Control-Allow-Credentials为true,而且Access-Control-Allow-Origin不能为*(具体请查看上一篇文章:CORS跨域介绍)。如果我们需要运行跨域的请求Origin有多个怎么办?或者我们后端根本不知道Origin的值,需要每次从请求头中获取比对怎么办?在拦截器中或过滤器中我们就可以使用request对象进行一些编码来实现。
package com.yyoo.springmvc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 指定允许其他域名访问,Access-Control-Allow-Credentials为true时,该值不能为* String origin = request.getHeader("origin"); if(origin != null && checkOrigin(origin)) { response.addHeader("Access-Control-Allow-Origin", origin); } // 允许请求携带cookie response.setHeader("Access-Control-Allow-Credentials", "true"); response.addHeader("Access-Control-Max-Age","86400"); // 响应类型 response.addHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS"); // 响应头设置 response.addHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With, X-authentication, X-client, X-Token, X_Requested_With"); return true; } private boolean checkOrigin(String origin){ List过滤器解决跨域问题originList = new ArrayList<>(); originList.add("http://localhost:8090"); originList.add("http://localhost:9090"); // ... for(String o : originList){ if(o.contains(origin)){ return true; } } return false; } }
@Component public class CorsFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; HttpServletRequest request = (HttpServletRequest) servletRequest; // String origin = request.getHeader("Origin"); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS"); response.setHeader("Access-Control-Max-Age", "86400"); // 为true时Access-Control-Allow-Origin不能为* response.setHeader("Access-Control-Allow-Credentials", "false"); // 此处为允许请求携带的所以请求头,如果要限制,可自行定义 response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers")); filterChain.doFilter(request, response); } @Override public void destroy() { } }
注:在使用shiro的时候拦截器或者其他方式无法解决跨域的问题,这个时候使用过滤器可以解决。(具体可以参考shiro使用token认证)
上一篇:CORS跨域介绍
下一篇:待续
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)