今天项目遇到一个问题,Spring中有一些请求会映射到
org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler
,一开始一直不知道是什么请求触发的,后来才知道是前端同学使用了W3C的CORS标准实现跨域。其中针对一些复杂请求,浏览器会先使用OPTIONS发出请求,这个请求就会被PreFlightHandler处理。趁机了解一下如何CORS原理和Spring的支持方法。
什么是CORS
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。
-
简单请求(simple request)
只要同时满足以下两大条件,就属于简单请求。-
请求方法是以下三种方法之一:
HEAD GET POST
-
HTTP的头信息不超出以下几种字段:
Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
-
-
非简单请求(not-so-simple request)
凡是不同时满足上面两个条件,就属于非简单请求。
使用Options完成CORS非简单请求
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Spring MVC如何支持CORS
- 直接在方法上使用注解
@CrossOrigin
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@RequestMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
- Controller上使用注解
@CrossOrigin
@CrossOrigin(origins = "http://example.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
与JSONP的比较
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
网友评论