版权声明:本文为博主原创文章,遵循版权协议,转载请附上原文出处链接和本声明。
本文链接:
每篇一句
talk is cheap,show me the money.
前言
的全称是:跨域资源共享(Cross-origin resource sharing),它是浏览器的一个技术规范。 浏览器自己是可以发起跨域请求的(比如你可以外链一个外域的图片或者视频),但是脚本是不能跨域去获取这些资源的内容的。传统的ajax请求只能获取在同一个域名下的资源,但是Html5打破了这个限制:允许ajax发起跨域请求。跨域的解决方案有多种:JSONP、Flash、IFrame等,当然还有今天的主菜。
我有理由相信若你在前端使用过Ajax,你100%遇见过如下图这样的报错:
若你看到这样的报错,那么此次你的请求返回数据是失败的(请务必理解这句话)。但是,但是,但是若你查看调试工具的栏,发现这个URL请求的是有返回值的(并且http状态码是200,表示请求被服务端正常处理了),形如这样:
看似相悖的结果,这到底怎么回事???本文就告诉你答案
同源策略
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。该策略是浏览器最核心也最基本的安全功能,同源指的是:同协议、同域名、同端口。
它的核心思想可以理解为:我只相信我同一个域的资源,来自于其它域的我都不可信,所以同源策略主要还是出于安全考虑的~
或只能访问同源(同协议、同域名、同端口下的内容。
CORS
它是的标准,它定义了在跨域访问资源时浏览器和服务器之间如何通信。它是为突破同源策略的限制而出现的一种官方标准的跨域解决方案。在实战场景中,跨域场景太为常见了(特别是当下前后端分离的开发模式),因此深入理解变得就异常的重要了(反倒前端工程师不用太了解)。
若想实现机制的跨域请求,是需要浏览器和服务器同时支持的。关于浏览器对的支持情况:现在都9012年了,so可以认为100%的浏览器都是支持的,再加上的整个过程都由浏览器自动完成,前端无需做任何设置,所以你的原来怎么用现在还是怎么用,它对前段开发人员是完全透明的。 所以呢,让此种机制生效的关键就在于服务器端,so作为服务端开发的我们,必须要玩转才可正常实现跨域通信。
机制的指导思想:自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否
为何需要跨域请求???
这是跨域请求产生的背景,最主要是随着互联网的发展,忘了改善网络应用程序的环境增强其功能,开发人员要求浏览器供应商允许跨域请求,能带来如下好处:
由此可见:跨域不仅仅是ajax的专属
上面都是成套成套的理论知识,过于抽象。那接下来我就是要通过本地的实例来模拟出跨域请求,从而依托于案例分析各种不同的case情况下的结果分析。
1、写一个前端HTML页面放于idea(idea可充当静态web服务器)
2、写一个控制器处理页面发送的ajax请求
3、利用idea的web服务器能力运行html页面,如下截图(本例使用的是标准的63342静态web端口)
请注意这个页面的访问地址的是,而点击这个"发送Ajax请求"按钮要发送的地址是,两者端口号不一样说明是不同的域,因此此ajax请求它必定属于跨域请求(CORS请求)。
4、点击发送按钮,查看控制台的结果 这个case的结果请完全参照文首的几张截图,此处就省略了
Tips:如果域名连不上服务端(比如服务端木有启动),它的报错一般都会是网络连接方面的问题,形如:,请注意区分~
如上结果,命名返回了200但浏览器偏偏还是报跨域异常,我相信这个让你感觉到十分的诧异和不解,那么接下来就围绕它来解释通这个问题。 但在我解释此现象之前,必须先要弄明白两个非常重要的CORS请求类型:简单请求,非简单请求(说明:这两种请求都属于CORS请求,这是大前提)。
简单请求、非简单请求
发送出来的请求分为两种:
很显然,不满足简单请求三大要求的便都是非简单请求喽。在实际生产应用场景中我们最为常见的非简单请求场景大致有如下三种case:
简单请求
对于这种请求,浏览器是直接发出请求,它的特点是:浏览器自动给加上一个的请求头,表示这个请求的来源(来自哪个源)。 比如上面案例的请求,它完全符合简单的请求的三大要求,所以它是一个简单请求,浏览器自动给它加上的头是:。 服务端可拿到这个源,然后判断服务端是否能够接受这个源从而决定是否同意这次请求(不同意or同意):
和简单请求相关的3个响应头如下:
Access-Control-Allow-Origin
该响应头是服务器必须返回的。它的值要么是请求时的值(可从request里获取),要么是这样浏览器才会接受服务器的返回结果。
Access-Control-Allow-Credentials
该响应头非必须,值是bool类型,表示是否允许发送
Tips:浏览器端默认情况下,不包括在CORS请求之中,若你想让浏览器带上,有需要的请自行研究一番吧~
Access-Control-Expose-Headers
该响应头非必须。顾名思义它要把response中的哪些头暴露给浏览器,让它可以获取到(默认情况下浏览器的XMLHttpRequest对象的方法只能获取到那些几个标准的响应头,若需要拿其它key,需要在这里指定)
请求成功案例
为了写出一个完全正确CORS简单请求,基于本例我只需要加一句代码即可:
再次点击按钮发送ajax请求结果如下:
大功告成。服务端不仅仅正常处理了请求,浏览器也接受了返回值。
对于简单请求请务必杜绝这种case:返回的状态码是200(服务端逻辑正常执行且正常返回了),浏览器不会接收结果,而是回调到方法去~
非简单请求
顾名思义,它比简单请求就要复杂些,不是简单请求的CORS请求都属于"非简单请求"(比如请求方法是或)。它最大的一个特点是:在发送正式请求通信之前,增加一次请求,这个请求称之为。
发送预检请求的过程完全由浏览器自动完成,开发者无需关心。
预检请求:它的作用是试探服务端是否能接受真正的请求,若服务器返回的状态码不是而是的话,那么浏览器将停止发送真正的请求。请求它具有如下特征:
下面先看一个非简单请求的例子,只需要把上例的Ajax注释的contentType放开即可,它便轻松成为了一个非简单请求了:
点击发送按钮,结果截图如下:
请求返回的状态码是403,所以真实的请求并未发送(network栏只有一个请求~)。浏览器自动添加的请求头中,最重要的仍然是这个头,例如我们生产环境的请求头如下:
另外两个请求头解释如下(虽然不是十分重要,但也是必须了解的):
这些请求头最终都发送给服务器,服务器收到这个预检请求后判断,检查这些头,确认允许跨域与否就可以做出相应的回应了(本例回应)。
和非简单请求相关的5个响应头如下:
Access-Control-Allow-Origin和Access-Control-Allow-Credentials
同上
Access-Control-Allow-Methods
必须的相应头,值是逗号分隔的字符串。表明我服务器可以支持的所有跨域请求的方法~可以用*代替
注:为何返回的不单单是马上要发真实请求的那个方法,而是多个呢???这是为了避免多次"预检"请求,提高效率。后面你可以看到它的功效
Access-Control-Allow-Headers
若请求头中包含,那响应头中这个头就是必须的,否则是非必须的。它的值是逗号分隔的字符串,表示我服务器支持的所有头字段,不限于预检请求中的头字段(但请包含它~)。可以用*代替
说明:若请求头中有,但是没有此响应头/响应头中的值不包含请求头的值。那么出现的奇异现象便是:请求正常200返回,但是真实请求就不会发送了。所以使用时请务必注意~
Access-Control-Max-Age(重要)
非必须。它表示需要缓存预检结果多长时间,单位是秒。比如表示将预检结果缓存10分钟,即表示10分钟之内同样的URL将不再发送预检请求。如果值是0表示不用缓存~
Tips:因为它对url生效,所以对那些默认的查询条件取当前时间戳的可千万别这么干了,一般我相信你精确到日期就够了而不用精确到毫秒吧,否则age就不生效了(每次都还得发送预检请求)
当然,你的浏览器也是可以禁用掉这种缓存的。
请求成功案例
它和简单请求的处理方式是不一样的,因为请求进入不了方法,所以在里向里设置请求头是无效的。 因此我们应该把设置相应头信息放在上才行,本例以的拦截器为例(生产上推荐使用):
请注意:这些添加header只能放在,放在里都将不生效(network里能看到这个头,但是无效果)
配置好后,点击按钮发送Ajax请求,结果截图如下:
从这张截图可以看到:我点击了3此发送切都成功了,再回头看看network:
非简单请求跨域成功。从截图的结果上还能看到它的功效,它能够减少请求的发送,从而减轻对服务端的访问压力。
如何理解对相同URL生效???
为了更好理解这个响应头的作用,我针对性的做出如下试验:
为了测试,我把设为了24小时,以保证缓存“永不过期”(控制变量法)
1、相同URL,不同的请求Method 页面改造如下,以保证先后发送一个请求和一个请求,同时也增加对请求的支持
答案:发送一次请求
2、相同URL,相同的请求Method(POST请求为例),不同的请求body体 答案:发送一次请求 3、相同的URL,不同Method、不同body体 答案:发送一次请求 4、不同的URL 答案:发送两次请求
实验证明:在缓存还生效的情况下,是否再次发送请求只和有关,只要URL不变,都不会再次发送请求了~ 这就警示我们:那些URL中有默认动态查询参数的(如当前时间戳)请务必注意了,如果每次都获取当前时间戳,那就导致每次URL都是不一样的,那就让这个响应头形同虚设了~
改进方案:默认动态查询参数不要精确到毫秒,绝大多数情况下精确到当前小时、天是足够了的,最不济分钟级别也够了吧~~~
CORS和JSONP对比
最终一个小知识点补充。是一个相对比较古老的用于解决跨域问题的技术了,对于新生代的程序员来说几乎可以忽略掉它,因为已经完全被新时代的所代替,把前浪拍死在沙滩上。
它哥俩都能解决浏览器Ajax请求资源的跨域问题,有些不同的点总结如下:
CORS带来的问题
总结
(跨域资源共享)是一种浏览器端的机制,它在现在前后端完全分离开发主流的今天还是蛮重要的概念,即使它比较简单。 需要注意的是:既然它是浏览器端的一种机制,所以它是可以被浏览器关闭这种机制的,至于如何do,有兴趣的可自行度娘~
在实战场景中:能控制服务器的情况下,一般都是服务器上正确配置CORS。可以在服务器API层(层)进行精细化控制配置,也可以在层进行统一配置(这样后端新加服务器不用再配置),最好配置上白名单而不是简单的粗暴的全是。
本文主要以介绍概念为主,然后结合一个实例介绍了它的使用和结果分析。但至少看完本文后你应该留有如下疑问待解决:
到此这篇前端跨域请求头(前端跨域请求方法)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/qdkf/13917.html