1、相同URL,不同的请求Method
页面改造如下,以保证先后发送一个GET请求和一个POST请求,同时Controller也增加对POST请求的支持
<script type="text/javascript"> var url = "http://localhost:8080/demo_war_war/test/cors"; function sendAjaxReq() { $.ajax({ type: "GET", contentType: "application/json", url: url, success: function (message) { console.log("成功!" + message); // 成功里立马再发一次请求:url一样 但是POST请求 $.ajax({ type: "POST", contentType: "application/json", url: url, success: function (message) { console.log("成功!" + message); } }); }, error: function (a, b, c, d) { console.log("失败!"); } }); } </script>
// 支持GET和POST请求的处理 @RequestMapping(value = "/test/cors", method = {GET, POST}) public Object testCors(HttpServletResponse response) { return "hello cors"; }
答案:发送一次OPTIONS请求
2、相同URL,相同的请求Method(POST请求为例),不同的请求body体
答案:发送一次OPTIONS请求
3、相同的URL,不同Method、不同body体
答案:发送一次OPTIONS请求
4、不同的URL
答案:发送两次OPTIONS请求
实验证明:在缓存还生效的情况下,是否再次发送OPTIONS请求只和URL有关,只要URL不变,都不会再次发送OPTIONS请求了~
这就警示我们:那些URL中有默认动态查询参数的(如当前时间戳)请务必注意了,如果每次都获取当前时间戳,那就导致每次URL都是不一样的,那就让Access-Control-Max-Age这个响应头形同虚设了~
改进方案:默认动态查询参数不要精确到毫秒,绝大多数情况下精确到当前小时、天是足够了的,最不济分钟级别也够了吧~~~
CORS和JSONP对比
最终一个小知识点补充。JSONP是一个相对比较古老的用于解决跨域问题的技术了,对于新生代的程序员来说几乎可以忽略掉它,因为已经完全被新时代的CORS所代替,把前浪拍死在沙滩上。
它哥俩都能解决浏览器Ajax请求资源的跨域问题,有些不同的点总结如下:
- JSONP只能实现GET请求(让支持其余请求将非常麻烦),CORS支持所有类型的HTTP请求
- 使用CORS,我们可以通过XMLHttpRequest直接完成请求发起和获取数据,因为都是这一个对象,所以处理错误更加方便
- JSONP的唯一优势:支持更老的浏览器(现在都9012年了,相信木有了)。CORS现已是官方的标准实现规范,几乎所有浏览器都支持得很好~
CORS带来的问题
- 带来的安全隐患,最主要的便是著名的跨站请求伪造CSRF(Cross-site request forgery),所以要做好这块的安全工作(建议可开启withCredentials的cookie认证)
- 因为增加了OPTIONS预检请求,无疑增加了系统的开销(本一个请求搞定的变成了需要两个请求),所以需要做好缓存策略以及确保缓存能够生效
- 可能影响到你的限流,需要特殊处理。由于OPTIONS请求和实际请求的发送时间间隔非常短,此时若你限流如:同一IP每秒只能访问1次,那真实请求就会被拒绝了,因此此时就要排除掉OPTIONS这种预检请求的影响
- 同样的,若你的Filter/拦截器里,若有需要也是要对OPTIONS方法进行特殊处理的,否则可能就会执行多次造成一些麻烦
相关阅读
CORS跨域资源共享(一):模拟跨域请求以及结果分析,理解同源策略【享学Spring MVC】
CORS跨域资源共享(二):详解Spring MVC对CORS支持的相关类和API【享学Spring MVC】
CORS跨域资源共享(三):@CrossOrigin/CorsFilter处理跨域请求示例,原理分析【享学Spring MVC】
总结
CORS(跨域资源共享)是一种浏览器端的机制,它在现在前后端完全分离开发主流的今天还是蛮重要的概念,即使它比较简单。
需要注意的是:既然它是浏览器端的一种机制,所以它是可以被浏览器关闭这种机制的,至于如何do,有兴趣的可自行度娘~
在实战场景中:能控制服务器的情况下,一般都是服务器上正确配置CORS。可以在服务器API层(Controller层)进行精细化控制配置,也可以在nginx层进行统一配置(这样后端新加服务器不用再配置),最好配置上白名单而不是简单的粗暴的全是*。
本文主要以介绍CORS概念为主,然后结合一个实例介绍了它的使用和结果分析。但至少看完本文后你应该留有如下疑问待解决:
- 有没有通用的跨域解决方案?
- Spring MVC对CORS的支持原理、使用方式是怎样的?
- 为何OPTIONS请求就不进入Handler方法进行处理呢