SpringBoot CORS支持
一只小熊猫呀 人气:0本章概要
- CORS 支持
- 配置类与 XML 配置
- 注册拦截器
CORS 支持
CORS (Cross-Origin Resource Sharing)是由 W3C 制定开发的一种跨域资源共享技术标准,其目的就是为了解决前端的跨域请求。在 Java EE 开发中,最常见的前端跨域请求解决方案是 JSONP ,但是 JSONP 只支持 GET 请求,而 CORS 则支持多种 HTTP 请求方法。
GET、POST、HEAD 请求流程:响应头中有一个 Access-Control-Orgin 字段,用来记录可以访问该资源的域。当浏览器收到这样的响应头信息后,提取 Access-Control-Orgin 字段中的值,发现该值包含当前页面所在的域,就知道这个跨域是被允许的。
DELETE、PUT 及 自定义请求等请求流程:以 DELETE 请求为例,当前端发起一个 DELETE 请求时,这个请求的处理会经过两个步骤。第一步,发送一个 OPTIONS 请求询问服务端是否具备该资源的 DELETE 权限,服务端给浏览器响应, Allow 头信息表示服务端支持的请求方法。第二步,发送 DELETE 请求,服务端再次给出一次响应。
无论是简单请求还是自定义请求,前端的写法都不变,额外的处理都是在服务端来完成的。在传统 Java EE 开发中,可以通过过滤器统一配置,而 Spring Boot 中对此则提供了更简洁的解决方案。
1. 创建SpringBoot工程
创建 Spring Boot 工程,添加 Web 依赖,如下
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2. 创建控制器
@RestController @RequestMapping("/book") public class BookController { @PostMapping("/") public String addBook(String name){ return "receive:"+name; } @DeleteMapping("/{id}") public String deleteBookById(@PathVariable long id){ return String.valueOf(id); } }
3. 配置跨域
跨域有两个地方可以配置,一个是直接在相应的请求方法上加注解:
@RestController @RequestMapping("/book") public class BookController { @PostMapping("/") @CrossOrigin(value = "http://localhost:8081",maxAge = 1800,allowedHeaders = "*") public String addBook(String name){ return "receive:"+name; } @DeleteMapping("/{id}") @CrossOrigin(value = "http://localhost:8081",maxAge = 1800,allowedHeaders = "*") public String deleteBookById(@PathVariable long id){ return String.valueOf(id); } }
代码解释:
- @CrossOrigin 中的 value 表示支持的域,这里表示来自 http://localhost:8081 域的请求是支持跨域的
- maxAge 表示探测请求的有效期,探测请求不用每次都发送,可以配置一个有效期,有效期过了之后才会发送探测请求,默认1800秒
- allowedHeaders 表示允许的请求头,“*” 表示所有的请求头都被允许
这种配置方式是一种细粒度的配置,可以控制到每一个方法上。也可以不再每个方法上加 @CrossOrigin 注解,而是采用全局配置,如下:
@Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/book/**") .allowedHeaders("*") .allowedMethods("*") .maxAge(1800) .allowedOrigins("http://localhost:8081"); System.out.println("进入跨域配置"); } }
代码解释:
- 全局配置需要自定义实现 WebMvcConfigurer 接口,然后实现接口中的 addCorsMappings 方法
- 在 addCorsMappings 方法中,addMapping 表示对哪种格式的请求路径进行跨域处理;allowedHeaders 表示允许的请求头,默认允许所有的请求头信息;allowedMethods表示允许的请求方法,默认是 GET 、POST 和 HEAD , * 表示支持所有的请求方法; maxAge表示探测请求的有效期;allowedOrigins表示支持的域
上面两种配置方式,选择一种即可,然后启动项目。
4. 测试
新建一个Spring Boot 项目,添加Web依赖,然后在 resources/static 目录下加入jquery.js并创建一个index.html文件,如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="jquery3.3.1.js"></script> </head> <body> <div id="contentDiv"></div> <div id="deleteResult"></div> <input type="button" value="提交数据" onclick="getData()"><br> <input type="button" value="删除数据" onclick="deleteData()"><br> <script> function getData() { $.ajax({ url: 'http://localhost:8081/book/', type: 'get', success: function (msg) { $("#contentDiv").html(msg); } }) } function deleteData() { $.ajax({ url: 'http://localhost:8081/book/99', type: 'delete', success: function (msg) { $("#deleteResult").html(msg); } }) } </script> </body> </html>
运行项目,访问"http://localhost:8081/index.html",查看结果
配置类与 XML 配置
Spring Boot 推荐使用 Java 完成相关的配置工作。在项目中,不建议将所有的配置放在一个配置类中,可以根据不同的需求提供不同的配置类,例如专门处理Spring Security 的配置类、提供 Bean 的配置类、Spring MVC 相关的配置类。这些配置上都需要添加 @Configuration,@ComponentScan 注解会扫描所有的 Spring 组件,也包括 @Configuration 。@ComponentScan注解 在项目入口类的 @SpringBootApplication 注解中已经提供,因此在实际项目中只需要按需提供相关配置类即可。
Spring Boot 中并不推荐使用 XML配置。如果需要使用 XML 配置,只需要在 resources 目录下提供配置文件 然后通过 @ImportResource 加载配置文件即可,例如,有一个 Hello 类,如下:
public class Hello { public String sayHello(String name){ return "hello" + name; } }
在resources 目录下新建 beans.xml 文件配置该类:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.sang.chapter04.Hello" id="hello"/> </beans>
然后创建 Bean 配置类,导入 XML 配置
@Configuration @ImportResource("classpath:beans.xml") public class Beans { }
最后在 Controller 中就可以直接导入 Hello 类使用了:
@RestController public class HelloController { @Autowired Hello hello; @GetMapping("/hello") public String hello(){ return hello.sayHello("嗨喽!"); } }
注册拦截器
Spring Boot 中提供了 AOP 风格的拦截器,拥有更加精细的拦截处理能力。Spring Boot 中拦截器的注册更加方便。
步骤1:创建一个 Spring Boot 项目,添加 spring-boot-starter-web 依赖。
步骤2:创建拦截器实现 HandlerInterceptor 接口
public class MyInterceptor1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("MyInterceptor1>>>preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("MyInterceptor1>>>postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("MyInterceptor1>>>afterCompletion"); } }
拦截器中的方法将按 preHandle --> Controller --> postHandle --> afterCompletion 的顺序执行。注意,只有 preHandle 方法返回 true 时后面的方法才会执行。当拦截器链内存在多个拦截拦截器时,postHandle 在拦截器链内的所有的拦截器返回成功时才会调用,而 afterCompletion 只有 preHandle 返回 true 才会调用,若拦截器链内的第一个拦截器的 preHandle 方法返回 false ,则后面的方法都不会执行。
步骤3:配置拦截器。定义配置类进行拦截器的配置,如下
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor1()) .addPathPatterns("/**") .excludePathPatterns("/hello"); } }
自定义实现 WebMvcConfigurer 接口,实现接口中的 addInterceptors 方法。其中,addPathPatterns表示拦截路径,excludePathPatterns 表示排除的路径。
步骤4:测试。在浏览器中访问 /hello 和 /hello2 接口,当访问 /hello2 时,打印日志如下:
MyInterceptor1>>>preHandle
MyInterceptor1>>>postHandle
MyInterceptor1>>>afterCompletion
加载全部内容