方便拿来用的同学使用,详细的请往下看。
@Configuration
public class CorsConfig {
@Bean
public 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);
}
}
跨域访问资源其实就是浏览器通过自身的权限,控制HTTP请求访问服务器资源,服务器和浏览器是基于HTTP请求头进行交流,例如:服务器通过Access-Control-Allow-Origin、Access-Control-Allow-Methods等类似的请求头告诉浏览器,我这个资源只能特定的源、某一组method才能进行访问。总结来说:服务器基于HTTP头声明哪些源通过浏览器的权限能访问服务器的哪些资源。
CORS权限验证的流程有两种,分别是简单请求和预检。
- 简单请求可以直接发起请求。
- 不是简单请求则需要预检,预检没问题之后才会发起真正的请求。
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
对象。告诉浏览器允许访问的源。
XMLHttpRequest.getResponseHeader可以访问的请求头,如果不设置只能访问Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。
这些请求头都是浏览器自己设置的,不能通过正常的API更改。
API
@RequestMapping("/cors")
@RestController
public class CorsController {
@GetMapping(value = "/html")
public String html(HttpServletResponse response) {
return "GET";
}
@DeleteMapping(value = "/delete")
public String delete(HttpServletResponse response) {
return "DELETE";
}
}
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");
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');
后面的就不去验证了,到这里我们已经知道CORS其实就是浏览器设置的一道权限,服务器可以通过Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Allow-Origin等特定的请求头去限制源的访问。
XMLHttpRequest
或 Fetch API 发起的跨源 HTTP 请求。@font-face
使用跨源字体资源),因此,网站就可以发布 TrueType 字体资源,并只允许已授权网站进行跨站调用。drawImage()
将图片或视频画面绘制到 canvas。跨域资源共享(CORS)