
参考:http://javascript.ruanyifeng.com/bom/cors.html
CORS(cross-origin resource sharing):跨源资源共享,允许浏览器对不同源的发出XMLHttpRequest请求,也就是克服ajax只能同源使用的限制。
现代浏览器会自动检测是否跨域,并自动完成一些操作。服务端同时对这种请求进行处理。所以需要浏览器端和服务端同时完成。
CORS分类
简单请求
请求方式为:HEAD、GET、POST
请求头字段限制为以下(一些通用请求头不列出)
| 键 | 值 |
|---|---|
| Accept | |
| Accept-Lanuage | |
| Last-Event-ID | |
| Content-Type | application/x-www-form-urlencoded、multipart/form-data、text/plain |
注意这种方式是为了和表单请求相对应。表单请求就是简单请求,并且是可以跨源的。这样是为了避免开发者使用表单请求,而不是使用ajax。
复杂请求
GET /cros HTTP/1.1 Origin: http://api.bob.com Host: api.bob.com Accept-Language: zh-CN Connection: alive User-Agent: Mozilla/5.0
浏览器对于简单请求会发出一个带有Origin的请求信息,标注了这个请求来自的源。
2 服务器处理不进行处理,直接返回(是的,可以直接返回结果)。此时浏览器可以查看结果(但是不能处理),因为返回请求头没有Access-Control-Allow-Origin字段的话,会抛出一个异常,被XMLHttpRequest的onerror函数捕获。
处理
服务端添加返回header
public Map first(HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Customize-Header", "xiao");
HashMap hashMap = new HashMap();
hashMap.put("name", "xiaojianbiao");
return hashMap;
}
其他头部信息
| 键 | 值 | 是否必须 | 作用 |
|---|---|---|---|
| Access-Contorl-Allow-Origin | *,Origin对应的值 | 是 | |
| Access-Control-Allow-Credentials | true | 否 | 是否允许浏览器发送cookie |
| Access-Control-Expose-Headers | 字符串 | 否 | 允许浏览器获取的额外的header字段(否则只能获取特定的header字段) |
除了服务端允许发送cookie(主要是复杂请求,会有预检请求),浏览器端也要设置发送cookie(默认情况下是不发送的)
var xHttp = new XMLHttpRequest(); xHttp.withCredentials = true;
请求方式是DELETE、PUT,或Content-Type是application/json等格式。
2.1 流程 1 发送预检请求请求代码
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML =
this.responseText;
}
};
xhttp.open("PUT", "http://localhost:8089/demo/demo_get.asp", true);
xhttp.setRequestHeader("Content-Type", "application/json")
xhttp.send();
请求信息(预检)
OPTIONS /demo/demo_get.asp HTTP/1.1 Host: localhost:8089 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Access-Control-Request-Method: PUT Access-Control-Request-Headers: content-type Origin: https://www.w3school.com.cn
OPTIONS类型的请求,附带着将要进行CROS请求的方法类型(Access-Control-Request-Method),额外的请求header字段(Access-Control-Request-Headers)。
2 预检回应HTTP/1.1 200 Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET,HEAD,POST Access-Control-Allow-Headers: content-type Access-Control-Max-Age: 1800 Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
手动添加response的header的Access-Control-Allow-Origin字段。
@RequestMapping(value = "/demo/demo_get.asp")
public Map first(HttpServletRequest request, HttpServletResponse response) {
response.addcookie(cookie);
response.setHeader("Access-Control-Allow-Origin", "*");
HashMap hashMap = new HashMap();
hashMap.put("name", "xiaojianbiao");
return hashMap;
}
注意:这种方式只能处理简单请求,如果是复杂请求的预检阶段会被拦截从而报403错误。
3.2 注解使用@CrossOrigin注解,这种方式可以解决复杂请求403错误问题
@CrossOrigin(origins = "*")
@RequestMapping(value = "/demo/demo_get.asp")
public Map first(HttpServletRequest request, HttpServletResponse response) {
HashMap hashMap = new HashMap();
hashMap.put("name", "xiaojianbiao");
return hashMap;
}