前言
在发布数据埋点工程后,前端访问时发生了跨域错误。经过问题分析排查发现,Kong网关里没有允许OPTIONS请求导致跨域错误。通过这个问题再对CORS原理梳理一下,知其所以然。
CORS原理分析
- 浏览器同源策略阻止跨域请求(请求1和请求2不一致)
- 浏览器和服务器使用HTTP头传递跨域请求的行为方式(下图来自cors-in-cation)
2.1 XMLHttpRequest对象将包含一个withCredentials属性,是否为true检查浏览器是否支持CORS
2.2 浏览器收到响应后,检查响应头Access-Control-Allow-Origin,判断服务器是否允许跨域请求。如果请求无效,浏览器将记录错误到控制台,然后触发XMLHttpRequest’onerror事件(找前端搞个页面验证一下)
prefligt request(预检请求)
-
在某些情况下,仅Access-Control-Allow-Origin 响应头是不够的,对服务器有特殊要求的非简单请求(比如PUT或DELETE方法,或者Content-Type字段的类型是application/json),需要在正式请求前增加一次预检请求
-
同时满足以下两个条件,就是简单请求(否则为非简单请求)
2.1 请求方法是以下三种方法之一:HEAD、GET、POST
2.2 HTTP的头信息不超出以下几种字段:
(1)Accept
(2)Accept-Language
(3)Content-Language
(4)Last-Event-ID
(5)Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain -
浏览器通过预检请求来请求权限,预检请求是浏览器在实际请求之前发送的一个小请求。包含使用哪种HTTP方法以及是否存在任何自定义HTTP头信息
项目跨域配置
- springboot后台配置跨域过滤器:CorsFilter
@Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); final CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); return new CorsFilter(urlBasedCorsConfigurationSource); }
- 因为对于非简单请求会发预检请求,所以网关路由要允许OPTIONS方法通过(自己因为没配,导致一直报跨域错误)
束语
留意日常工作中的每一个bug,问题驱动在调式代码时会更有方向感,在排查问题时多反思,可以有很多收获。这里因为时间问题(还要好多需求没写),只问了自己既然有Access-Control-Allow-Origin响应头,为什么还要发送预检请求?其实可以接着问问自己为什么非简单请求就要发送预检请求呢?等等,有时间继续学习