CORS目录
- 一、SpringBoot 跨域设置
- 二、CORS
- (1)总结的图如下
- (2)简单请求满足的条件
- (3)响应头
- (4)请求头
- (5)使用XMLHttpRequest进行跨域访问
- 1. Access-Control-Allow-Methods
- 2. Access-Control-Allow-Headers
- 3. 总结
- 三、跨域的情况
- 四、参考
一、SpringBoot 跨域设置
方便拿来用的同学使用,详细的请往下看。
@Configuration
public class CorsConfig {@Beanpublic CorsFilter corsFilter() {CorsConfiguration htmlGet = new CorsConfiguration();htmlGet.addAllowedOrigin("*");htmlGet.setAllowCredentials(true);htmlGet.addAllowedMethod("*");htmlGet.addAllowedHeader("*");htmlGet.addExposedHeader("*");UrlBasedCorsConfigurationSource corsConfigurationSource= new UrlBasedCorsConfigurationSource();corsConfigurationSource.registerCorsConfiguration("/**", htmlGet);return new CorsFilter(corsConfigurationSource);}
}
二、CORS
跨域访问资源其实就是浏览器通过自身的权限,控制HTTP请求访问服务器资源,服务器和浏览器是基于HTTP请求头进行交流,例如:服务器通过Access-Control-Allow-Origin、Access-Control-Allow-Methods等类似的请求头告诉浏览器,我这个资源只能特定的源、某一组method才能进行访问。总结来说:服务器基于HTTP头声明哪些源通过浏览器的权限能访问服务器的哪些资源。
(1)总结的图如下
CORS权限验证的流程有两种,分别是简单请求和预检。
- 简单请求可以直接发起请求。
- 不是简单请求则需要预检,预检没问题之后才会发起真正的请求。
(2)简单请求满足的条件
- 使用下列方法之一:
GET
HEAD
POST
- 除了被用户代理自动设置的标头字段(例如
Connection
、User-Agent
或其他在 Fetch 规范中定义为禁用标头名称的标头),允许人为设置的字段为 Fetch 规范定义的对 CORS 安全的标头字段集合。该集合为:Accept
Accept-Language
Content-Language
Content-Type
(需要注意额外的限制)Range
(只允许简单的范围标头值 如bytes=256-
或bytes=127-255
)
Content-Type
标头所指定的媒体类型的值仅限于下列三者之一:text/plain
multipart/form-data
application/x-www-form-urlencoded
- 如果请求是使用
XMLHttpRequest
对象发出的,在返回的XMLHttpRequest.upload
对象属性上没有注册任何事件监听器;也就是说,给定一个XMLHttpRequest
实例xhr
,没有调用xhr.upload.addEventListener()
,以监听该上传请求。 - 请求中没有使用
ReadableStream
对象。
(3)响应头
- Access-Control-Allow-Origin
告诉浏览器允许访问的源。
- Access-Control-Expose-Headers
XMLHttpRequest.getResponseHeader可以访问的请求头,如果不设置只能访问Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。
- Access-Control-Max-Age
- Access-Control-Allow-Credentials
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
(4)请求头
这些请求头都是浏览器自己设置的,不能通过正常的API更改。
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Header
(5)使用XMLHttpRequest进行跨域访问
API
@RequestMapping("/cors")
@RestController
public class CorsController {@GetMapping(value = "/html")public String html(HttpServletResponse response) {return "<div>GET</div>";}@DeleteMapping(value = "/delete")public String delete(HttpServletResponse response) {return "<div>DELETE</div>";}
}
1. Access-Control-Allow-Methods
function get() {const xhr = new XMLHttpRequest();xhr.open('GET', 'http://localhost:8080/cors/html')xhr.onreadystatechange = function() {console.log('status', xhr.readyState)}xhr.send();
}
@Bean
public CorsFilter corsFilter() {CorsConfiguration htmlGet = new CorsConfiguration();htmlGet.addAllowedOrigin("null");htmlGet.addAllowedMethod("DELETE");UrlBasedCorsConfigurationSource corsConfigurationSource= new UrlBasedCorsConfigurationSource();corsConfigurationSource.registerCorsConfiguration("/cors/html", htmlGet);return new CorsFilter(corsConfigurationSource);
}
可以看到CORS异常了,XMLHTTPRequest请求是GET,服务器Access-Control-Allow-Methods是DELETE,换成人话说:服务器只允许DELETE请求。
把htmlGet.addAllowedMethod("DELETE");
改成htmlGet.addAllowedMethod("GET");
2. Access-Control-Allow-Headers
function get() {const xhr = new XMLHttpRequest();xhr.open('GET', 'http://localhost:8080/cors/html')xhr.onreadystatechange = function() {console.log('status', xhr.readyState)}xhr.setRequestHeader('headxxx', 'a');xhr.send();
}
@Bean
public CorsFilter corsFilter() {CorsConfiguration htmlGet = new CorsConfiguration();htmlGet.addAllowedOrigin("null");htmlGet.addAllowedMethod("DELETE");htmlGet.addAllowedHeader("Token");UrlBasedCorsConfigurationSource corsConfigurationSource= new UrlBasedCorsConfigurationSource();corsConfigurationSource.registerCorsConfiguration("/cors/html", htmlGet);return new CorsFilter(corsConfigurationSource);
}
因为我们的请求头headxxx不在简单请求的范围内(上面写了),所以浏览器发起了预检。服务器只接收Token请求头,所以浏览器通过对比后发现http请求不满足服务器的规则。不是简单请求都会触发预检。
把xhr.setRequestHeader('headxxx', 'a');
改成xhr.setRequestHeader('Token', 'a');
3. 总结
后面的就不去验证了,到这里我们已经知道CORS其实就是浏览器设置的一道权限,服务器可以通过Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Allow-Origin等特定的请求头去限制源的访问。