摘要:本文学习了Spring MVC中的跨域请求处理。
环境
Windows 10 企业版 LTSC 21H2 Java 1.8 Tomcat 8.5.50 Maven 3.6.3 Spring 5.3.23
1 概述 跨域(Cross Origin Resource Sharing,CORS)是指从一个域名的网页去请求另一个域名的资源。由于浏览器的同源策略,默认情况下不允许跨域请求,这是为了保护用户信息安全。
同源策略要求请求的协议、域名和端口都必须相同,否则就是跨域请求。
出现跨域时,浏览器控制台会提示:
log 1 2 Access to XMLHttpRequest at '目标URL' from origin '网页URL' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
2 预检请求 浏览器在发送跨域请求时,如果请求是复杂请求,浏览器会先发送OPTIONS预检请求,询问服务器是否允许该跨域请求。
请求分为简单请求和复杂请求,简单请求会直接发送请求,复杂请求会先发送OPTIONS预检请求。
2.1 简单请求 简单请求的要求,必须全部满足:
请求方法是简单类型:
请求头中只包含简单的字段
Accept:告知客户端浏览器支持的响应类型。
Accept-Language:告知服务器浏览器支持的语言。
Content-Language:告知服务器传输内容使用的语言。
Content-Type:告知浏览器传输内容使用的内容类型,只能是application/x-www-form-urlencoded、multipart/form-data、text/plain其中之一。
简单请求对服务器没有安全影响,浏览器会直接发送请求。
2.2 复杂请求 复杂请求的要求,满足一个即可:
请求方法不是简单类型。
请求头中包含自定义请求头,或者Content-Type是JSON格式或者XML格式。
复杂请求对服务器有安全影响,浏览器会先发送OPTIONS预检请求,询问服务器是否允许该跨域请求。
服务器在收到OPTIONS预检请求后,会在响应头中添加允许跨域的相关字段:
Access-Control-Allow-Origin:指定允许跨域请求的域名,*表示允许所有域名。
Access-Control-Allow-Methods:指定允许跨域请求的方法,多个方法用逗号分隔。
Access-Control-Allow-Headers:指定允许跨域请求的请求头,多个头用逗号分隔。
Access-Control-Expose-Headers:指定允许客户端访问的响应头,多个头用逗号分隔。
Access-Control-Allow-Credentials:指定是否允许跨域请求携带认证信息,设置为true时必须指定允许跨域请求的域名。
Access-Control-Max-Age:指定预检请求的缓存时间,单位秒。
3 解决方案 常见的跨域解决方案包括:
JSONP:通过在请求中添加回调函数参数,将响应包裹在函数调用中,实现跨域,只支持GET请求。
CORS:通过在服务器端设置响应头,允许指定的域名跨域请求。
代理:通过在服务器端设置代理,将跨域请求转发到目标服务器,再将响应返回给客户端。
4 配置方式 4.1 局部配置 使用@CrossOrigin注解可以类级别和方法级别配置跨域,传入允许跨域请求的域名。
示例:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 @Controller @RequestMapping("/api") @CrossOrigin(origins = "http://localhost:8080") public class DemoController { @RequestMapping("/demo") @CrossOrigin(origins = "http://localhost:8080") @ResponseBody public String demo () { return "demo" ; } }
4.2 全局配置 4.2.1 半注解配置 在spring-mvc.xml配置文件中使用mvc:cors标签配置全局跨域策略:
spring-mvc.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:mvc ="http://www.springframework.org/schema/mvc" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd" > <context:component-scan base-package ="com.example.controller" /> <mvc:annotation-driven /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/views/" /> <property name ="suffix" value =".jsp" /> <property name ="contentType" value ="text/html;charset=UTF-8" /> </bean > <mvc:cors > <mvc:mapping path ="/api/**" allowed-origins ="http://localhost:8080" allowed-methods ="GET, POST, PUT, DELETE, OPTIONS" allowed-headers ="Origin, Content-Type, Accept, Authorization" exposed-headers ="Content-Length" allow-credentials ="true" max-age ="3600" /> </mvc:cors > </beans >
4.2.2 全注解配置 在配置类中配置全局跨域策略:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Configuration @EnableWebMvc @ComponentScan("com.example.controller") public class WebConfig implements WebMvcConfigurer { @Bean public ViewResolver viewResolver () { InternalResourceViewResolver resolver = new InternalResourceViewResolver (); resolver.setPrefix("/WEB-INF/views/" ); resolver.setSuffix(".jsp" ); resolver.setContentType("text/html;charset=UTF-8" ); return resolver; } @Override public void addCorsMappings (CorsRegistry registry) { registry.addMapping("/api/**" ) .allowedOrigins("http://localhost:8080" ) .allowedMethods("GET" , "POST" , "PUT" , "DELETE" , "OPTIONS" ) .allowedHeaders("Origin" , "Content-Type" , "Accept" , "Authorization" ) .exposedHeaders("Content-Length" ) .allowCredentials(true ) .maxAge(3600 ); } }
条