如果是非简单请求, 浏览器就不会真的马上去发这个请求, 会先发预检命令 (发试探的请求)
发送json的ajax请求
$.ajax({
type : "post",
url: "http://localhost:8080/test/postJson",
//这样传json是属于非简单请求 会先预检
contentType : "application/json;charset=utf-8",
data: JSON.stringify({name: "xiaofengqing"}),
success: function(json){
result = json;
}
});
后端代码
@PostMapping("/postJson")
public ResultBean postJson(@RequestBody User user) {
System.out.println("TestController.postJson()");
return new ResultBean("postJson " + user.getName());
}
对应这样的非简单请求,浏览器的会先发这样一条预检命令
但是如图↑后端返回的响应头里面,没有写明同意这个 content-type
浏览器看到后, 就知道预检不通过了 报错
之后就不会真的去发生这个非简单请求,
后端那个controller根本没进去
在过滤器里面 加这么一句,特地去加预检命令要求的这个头
res.addHeader("Access-Control-Allow-Headers", "Content-Type");//允许非简单 就是往这里传json
试一试:
这样就能通过
浏览器发预检命令 请求头里面说 需要响应头里面同意Content-Type
Access-Control-Request-Headers: content-type
响应头里面有 同意头Content-Type
Access-Control-Allow-Headers: Content-Type
预检命令成功,
就会真的去补发我们要的那个非简单请求
带自定义头
再来一个 带自定义头的请求(明显也是非简单请求)
$.ajax({
type : "get",
url: "http://localhost:8080/test/getHeader",
//加头的方法1
headers:{
"x-header1" : "AAA"
},
//加头的方法2
beforeSend: function(xhr){
xhr.setRequestHeader("x-header2","BBB")
},
success: function(json){
result = json;
}
});
服务端
@GetMapping("/getHeader")
public ResultBean getHeader(
@RequestHeader("x-header1") String header1,
@RequestHeader("x-header2") String header2) {
System.out.println("TestController.getHeader()");
return new ResultBean("getHeader " + header1 + " " + header2);
}
浏览器控制台报错
:8081/#:1 Failed to load http://localhost:8080/test/getHeader: Request header field x-header2 is not allowed by Access-Control-Allow-Headers in preflight response.
确实 浏览器发出的请求头里面有写这个要求
Access-Control-Request-Headers: x-header1,x-header2
而相应头里面 没有满足这个要求
最终版
请求头里面要求响应头里面写支持什么头 都一律支持
String headers = req.getHeader("Access-Control-Request-Headers");
if (!org.springframework.util.StringUtils.isEmpty(headers)) {
res.addHeader("Access-Control-Allow-Headers", headers);
}
res.addHeader("Access-Control-Max-Age", "3600");//options预检命令缓存 这个时间段
缓存
每次非简单请求 都向服务端发2次请求 太没效率了
服务端 还可以让浏览器缓存预检命令结果,
再发非简单请求 不用再给服务端发预检命令了,可以直接看浏览器直接的缓存
res.addHeader("Access-Control-Max-Age", "3600");//单位是秒
//options预检命令缓存 这个时间段:1小时