AJax技术

再也不学AJAX了(三):跨域获取资源②JSONP CORS(3)

字号+ 作者:H5之家 来源:H5之家 2017-12-13 12:36 我要评论( )

与简单AJAX跨域请求不同,复杂的AJAX跨域请求一共会发送两次HTTP请求,其中第一次为 查询请求 ,第二次才是我们正式的 AJAX跨域请求 。为什么多出了一次查询请求呢?道理其实很简单,我们想象一下当发送复杂的AJAX

与简单AJAX跨域请求不同,“复杂“的AJAX跨域请求一共会发送两次HTTP请求,其中第一次为” 查询请求 “,第二次才是我们正式的” AJAX跨域请求 “。为什么多出了一次”查询请求“呢?道理其实很简单,我们想象一下当发送”复杂“的AJAX跨域请求时,浏览器最先拿到请求开始识别,然后发现这个请求并不“单纯”(不满足简单跨域AJAX请求标准),于是感到十分疑惑的浏览器会试探的沿着请求的地址向服务端发问,询问服务端是否允许异域的客户端向它发送额外的请求信息,这一次“发问”,即是第一次HTTP请求,即“查询请求”。而服务端当然也会这次“发问”给出相应的回答,然后浏览器就会根据回答的结果决定是否继续发送该跨域AJAX请求。

让我们看看具体的实现细节:

首先,让我们创造出一个“复杂”的AJAX跨域请求:

var url = '' var xhr = new XMLHttpRequest() xhr.open('put', url, true) // 这里我们设置请求的方式为'put' xhr.setRequestHeader('X-Custom-Header', 'Value') // 这里我们自定义了一个请求头字段 xhr.send()

当浏览器识别到该请求“并不简单”时,就会自动向服务其发送一个“查询请求”,其报头信息大致如下:

OPTIONS /cors HTTP/1.1 Origin: Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: another.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...

注意这次“查询请求”使用了“OPTIONS”的请求方法,表明了这是一个查询请求。请求头部的信息说明了 请求来源的域 , 请求使用的HTTP方法 以及 请求额外发送的头部字段 。

让我们再转换至服务器视角,当服务端接收到浏览器发来的这样一个查询请求后,就可以判断出是否应该接收该请求。如果想要向浏览器表示允许该请求,则会返回这样的响应报文:

HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61(Unix) Access-Control-Allow-Origin: Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header // 该字段值为以“,”号分割的字符串 Content-type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain

读到这里我们已经大概猜的出服务端向浏览器传递的信息了:

  • 首先, Access-Control-Allow-Origin 字段向浏览器说明了发起AJAX请求的域是被服务器认可的(注意这个字段的值也可以为一个“*”号);
  • 其次, Access-Control-Allow-Methods 字段向浏览器说明了服务器接收跨域AJAX的请求方式;
  • 最后, Access-Control-Allow-Headers 字段向浏览器说明了服务器允许跨域AJAX额外发送的报头信息;
  • 当浏览器收到服务端这样的表示同意请求的响应后,就会正常发送接下来的跨域AJAX请求,而服务器也会正常的回应。值的一提的是,在服务端与客户端整个跨域AJAX请求的交互中, Access-Control-Allow-Origin 头信息自始至终都是必须携带的。

    而当服务器在检查“查询请求”后,如果不同该请求,则会返回一个正常的HTTP响应,报文中包含任何与CORS规范有关的报头字段,此时,浏览器就会心领神会的明白服务器拒绝接收发出的跨域AJAX请求,因此会返回一个错误状态(可以被XML对象实例使用onerror回调函数捕获)并在控制台打印一条错误信息:

    XMLHttpRequest cannot load Origin is not allowed by Access-Control-Allow-Origin

    至此,无论是“简单”的跨域AJAX请求还是“复杂”的跨域AJAX请求,我们都已经清楚的知晓了他们的运作原理,这真是件了不起的事情。但是先别着急庆祝,我们刚才还遗漏了一个话题没有谈到:“节约复杂AJAX跨域请求的HTTP请求数”。

    相信你还记的,对于“复杂”的跨域AJAX请求,浏览器会向服务器发送两次HTTP请求,虽然实际上两次HTTP请求与一次HTTP请求所耗费的时间几乎难以感知,但是如果我们有办法一次搞定,又为什么还要重复做两次呢?

    对于服务器而言,“一次搞定”的方法就在于,在浏览器第一次发送复杂的跨域AJAX查询请求时,在响应报头中添加 Access-Control-Max-Age 字段,这是一个可选的字段,它用来指定本次查询请求的有效期,单位为秒。也就是说,通过该字段,服务器拥有了告知浏览器“这个请求我批准了,X秒以内不需要再向我确认”的能力。至此,我们成功的将接下来的跨域请求数由两次节约为一次!

    三、小结

    一口气看到这里?真不容易! 希望这是值得的,让我们总结一下我们在本文中都谈到了些什么。首先,我们谈到了我们何时需要发起跨域AJAX请求的问题,做到了“知其然”。其次,我们深入探讨了使用JSONP技术和CORS规范实现发送跨域AJAX请求的细节,成功达到了我们“知其所以然”的目标。相信现在的你已经对向他人谈论“跨域”这个主题充满自信。真的很棒对吧?

    如果你依然觉得意犹未尽,不妨接着和我继续深入这个主题,看看实现跨域共享资源的另外两种“时髦”的方式:使用 postMessage 和 webSocket。

    感兴趣吗?休息一下,然后再回来,目前为止你表现的都非常出色!:raised_hands: 。

    分享给小伙伴们:

    本文标签: ajax,jsonp,跨域/">ajax,jsonp,跨域

    相关文章

    发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

  • 本类最热新闻

  •  

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 通过Ajax方式上传文件,使用FormData进行Ajax请求

      通过Ajax方式上传文件,使用FormData进行Ajax请求

      2017-12-13 14:55

    • PHP ajax 分页类代码

      PHP ajax 分页类代码

      2017-12-12 18:14

    • Access-Control-Allow-Origin与Ajax跨域解决方法

      Access-Control-Allow-Origin与Ajax跨域解决方法

      2017-12-12 18:00

    • 从零开始学习jQuery (六) AJAX快餐(10)

      从零开始学习jQuery (六) AJAX快餐(10)

      2017-12-12 09:22

    网友点评
    s