> 编程开发 > AJAX相关 >
再也不学AJAX了(三):跨域获取资源②JSONP & CORS 2017-12-06 16:42 出处:清屏网 人气:
浏览器的“同源策略”固然保障了互联网世界的数据隐私与数据安全,但是如果当我们需要使用AJAX跨域请求资源时,“同源策略”又会成为开发者的阻碍。在本文中,我们会简单介绍需要跨域请求资源的两种情景,然后,详细解释目前主流的四种跨域请求资源方案。
让我们开始吧!
一、何时需要跨域试想,当我们拥有多个站点,并且这些站点又经常共享相同的数据,那么为每个站点存储一份数据看起来就蠢透了。更好的方案是,我们建设一台静态资源存储服务器,然后让我们的所有站点都从这一台服务器上获取资源。很理想的方案,但是现实中,我们首要解决的问题便是浏览器的“同源策略”,别忘了,不同域之间无法通过AJAX技术获取资源。这是需要跨域获取资源的主要情景。
另外,站在互联网“开放,平等,自由”精神的角度上讲,如果所有人的数据都被设置为只有同域才能访问,那么互联网世界未免也太无聊了,如果我就是想要与更多的人分享我的数据,难道不应该有办法让我做到这一点吗?
当然有办法,下面我们就将一一解释当下主流的跨域请求资源方式。
二、跨域请求资源方案我们将主要介绍以下四种跨域请求资源的方案,并逐一解释他们的原理,实用方式以及优缺点,希望你和我一样有耐心,耐心总是能带来回报:
在开始下面的内容之前,我们首先需要强调一点, 无论是怎样的跨域资源获取方案,本质上都需要服务器端的支持 。跨域获取资源之所以能够成功,本质是服务器默许了你有权限获取相应资源。下面我们所运用的种种方式,实际上是客户端和服务端互相配合,绕过同源策略进行数据交互的工作,千万不要误以为掌握了下述技术后,我们就能成为一个黑客 ����♂️。
(一)野路子出身却异常好用的方式:JSONP正如标题所描述的那样,JSONP技术是早期某个(些?)聪明的程序员发明的跨域资源获取方式,由于该技术的简单易用,逐渐变得越来越流行,最终成为经典的跨域获取资源方案。
JSONP是“JSON with padding”的简写,我将其翻译为“被包裹的JSON”,当你看完这个章节,你一定会觉得这个名字相当贴切。
让我们模拟一下当初想到JSONP技术的高手程序员是如何推理的:
首先,我们应该清楚的认识到,浏览器的“同源策略” 只是阻止了通过AJAX技术跨域获取资源,而并没有禁止跨域获取资源这件事本身 ,正因如此,我们可以通过 <link> 标签, <img> 标签以及 <script> 标签中的 href 属性或 src 属性获取异域的CSS,JS资源和图片(虽然我们其实并不能读取这些资源的内容)。
其次,我们知道(也许你不知道,但是,还记得吗,我在模拟那个高手程序员?) <script> 标签通过 src 属性加载的JS资源,实际上只是将JS文件内容原封不动的放置在 <scritp> 的标签内,并没有什么神奇之处!
也就是说,如果我们的sayHi.js文件只有这样一段代码:
// sayHi.js alert('Hi')当我们在HTML文件中,成功加载sayHi.js文件时,浏览器只不过是做了如下操作:
<!-- 加载前 --> <script src="sayHi.js"></script> <!-- 加载后 (为了方便阅读,我格式化了代码)--> <script src="sayHi.js"> alert('Hi') </script>这意味着什么呢?这意味着被加载的文件与HTML文件下的其他JS文件共享一个全局作用域。也就是说, <scritp> 标签加载到的资源是可以被全局作用域下的函数所使用的!
但是慢着!如果 <script> 标签加载到的一些数据并不符合JavaScript语法规定的 数据类型 ,JavaScript就无法处理这些错误不是吗?而且就算数据类型正常了,我们还应该将数据存储于一个 变量 内,然后调用这个变量...
说的没错!不过我们其实已经离正确答案很近了。
还记的我们这一方案的名称吗?JSONP!,也就是说我们已经约定好了数据的格式为JSON,这是JavaScript可以处理的数据类型,并且JSON格式的数据可以承载大量信息。那么有关 变量 的问题呢?这个回答则更巧妙些,因为我们会通过向服务器传入一个函数的方式,将数据变为函数的参数,让我们直接看看JSONP的使用方式:
1. function handleResponse(response) { 2. alert(`You get the data : ${response}`) 3. } 4. const script = document.createElement('script') 5. script.src = '?callback=handleResponse' 6. document.body.insertBefore(script, document.body.firstChild)很容易看到,我们在1-3行中创建了一个函数,该函数用来处理我们将要获得的数据,该函数的参数 response 即是服务器响应的数据。在4-6行中我们所做的是利用JavaScript动态生成一个script标签,并将其插入HTML文档。但是注意第5行我们制定的src值,在URL末尾,我们有这样一段查询参数 callback=handleResponse ,callback的值正是我们先前创建的函数。
事情开始变得有些令人困惑了,究竟发生了什么呢?我们如何通过上述代码最终实现跨域获取资源?
答案就藏在服务端的代码中,当服务端支持JSONP技术时,会做如下一些设置:
此时该文件内容看起来就像这样:
handleResponse(response) // response为被请求的JSON格式的数据因此,当资源加载到位,内容显示在script标签内时,浏览器引擎会执行这条语句,我们想要的数据就可以被我们以任何想要的方式处理了。真不可思议!
你现在知道为什么这项技术被命名为JSONP了吧?那个“padding”指的就是我们的“callback”函数,真是恰如其名。