function https(url,type,data,header,callback) {
$.ajax({
url:url,
type:type,
data:data,
contentType:'application/json',
headers:header,
crossDomain:true,
success:function (data,status) {
console.log(data);
if(data.errorNo == "20001" || data.errorNo == "20002"){
//令牌失效
window.location.href = "./lyear_pages_login.html";
}else if(data.errorNo == "0"){
callback(data,status);
}else{
alert(data.errorInfo);
}
},
error:function (XMLHttpRequest,textStatus,errorThrown) {
if(textStatus==='timeout'){
alert('請求超時');
setTimeout(function(){
alert('重新请求');
},2000);
}
window.location.href = "./lyear_pages_login.html";
}
})
}
使用改模板发送一个请求到本地服务器的时候,会出现以下的错误:403
General:
Request URL: http://localhost:9090/....
Request Method: OPTIONS
Status Code: 403
Remote Address: [::1]:9090
Referrer Policy: no-referrer-when-downgrade
Response Headers:
Connection: keep-alive
Date: Sat, 28 Mar 2020 07:12:49 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
Request Headers:
Provisional headers are shown
Access-Control-Request-Headers: authentication,content-type
Access-Control-Request-Method: GET
Origin: http://localhost:63342
Referer: http://localhost:63342/lyear_2_LightYear-admin/index.html
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
可以看到这个请求是OPTIONS的,而不是我们预期的GET或是POST。
原因在于:https://www.cnblogs.com/wanghuijie/p/preflighted_request.html
也就是这是一个Preflighted Request,所以发送真正的请求之前会发送一个OPTIONS请求用于试探服务器是否能接受真正的请求。如果options获得的回应是拒绝性质的,比如404\403\500等http状态,就会停止post、get等请求的发出。
关于Preflighted Request(带预检的跨域请求)发生在:
(文档地址:https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_request_headers)
- 请求方法不是GET/HEAD/POST
- POST请求的
Content-Type
并非application/x-www-form-urlencoded
,multipart/form-data
, 或text/plain
- 请求设置了自定义的
header
字段
以上封装的请求符合了2和3。而且在使用token验证和大量json数据的请求中是不可避免的。
解决方法:给OPTIONS请求一个正确的响应。
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
/**
*@Author: Czc on 2020/3/28 14:18
*@param:
*@return:
*@Description: 跨域请求配置
**/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
addCorsMappings方法对OPTIONS方法返回了允许的响应。
然后再发出真正的请求。
当然,就像登陆校验拦截器一样,也可以通过拦截器对请求进行处理,再响应的报文头部中加上跨域请求相关的字段。然后对于OPTIONS请求直接截断返回。其他的请求继续进行。