前端跨域请求原理及实践

一、 跨域请求的含义

浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用。

一般的,只要网站的 协议名protocol、 主机host、 端口号port
这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用。这也是我们下面实践的理论基础。我们利用 NodeJs 创建了两个服务器,分别监听
3000、 3001 端口(下面简称 服务器3000 与 服务器3001
),由于端口号不一样,这两个服务器以及服务器上页面通信构成了跨域请求。

在服务器3000 上有如下的页面:

服务器3000 上的请求页面中包含如下 JavaScript 代码:


  1. $(function() { 
  2.  
  3.     $("#submit").click(function() { 
  4.  
  5.         var data = { 
  6.  
  7.             name: $("#name").val(), 
  8.  
  9.             id: $("#id").val() 
  10.  
  11.         }; 
  12.  
  13.         $.ajax({ 
  14.  
  15.             type: 'POST', 
  16.  
  17.             data: data, 
  18.  
  19.             url: 'http://localhost:3000/ajax/deal', 
  20.  
  21.             dataType: 'json', 
  22.  
  23.             cache: false, 
  24.  
  25.             timeout: 5000, 
  26.  
  27.             success: function(data) { 
  28.  
  29.                 console.log(data) 
  30.  
  31.             }, 
  32.  
  33.             error: function(jqXHR, textStatus, errorThrown) { 
  34.  
  35.                 console.log('error ' + textStatus + ' ' + errorThrown); 
  36.  
  37.             } 
  38.  
  39.         }); 
  40.  
  41.     }); 
  42.  
  43. });  

服务器3000 对应的处理函数为


  1. pp.post('/ajax/deal', function(req, res) { 
  2.  
  3.     console.log("server accept: ", req.body.name, req.body.id) 
  4.  
  5.     var data = { 
  6.  
  7.         name: req.body.name + ' - server 3000 process', 
  8.  
  9.         id: req.body.id + ' - server 3000 process' 
  10.  
  11.     } 
  12.  
  13.     res.send(data) 
  14.  
  15.     res.end() 
  16.  
  17. })  

请求页面返回结果:

此处数据处理成功。

由于数据请求一般都是由页面发送数据字段,服务器根据这些字段作相应的处理,如数据库查询,字符串操作等等。所以我们这里简单的处理数据(在数据后面加上字符串‘server 3000 process’),并且返回给浏览器,表示数据经过服务器端处理。

如果让 服务器3000 上的页面向 服务器 3001 发起请求会怎样呢?

将请求页面中的 ajax 请求路径改为:


  1. $.ajax({ 
  2.  
  3.     ... 
  4.  
  5.     url: 'http://localhost:3001/ajax/deal', 
  6.  
  7.     ... 
  8.  
  9. });  

服务器3001 对应的处理函数与 服务器3000 类似:


  1. app.post('/ajax/deal', function(req, res) { 
  2.  
  3.     console.log("server accept: ", req.body.name, req.body.id) 
  4.  
  5.     var data = { 
  6.  
  7.         name: req.body.name + ' - server 3001 process', 
  8.  
  9.         id: req.body.id + ' - server 3001 process' 
  10.  
  11.     } 
  12.  
  13.     res.send(data) 
  14.  
  15.     res.end() 
  16.  
  17. })  

结果如下:

结果证明了我们上面所说的端口号不同,发生了跨域请求的调用。

需要注意的是,服务器 3001 控制台有输出:


  1. server accept:  chiaki 3001 

这说明跨域请求并非是浏览器限制了发起跨站请求,而是请求可以正常发起,到达服务器端,但是服务器返回的结果会被浏览器拦截。

二、 利用 JSONP 实现跨域调用

说道跨域调用,可能大家首先想到的或者听说过的就是 JSONP 了。

2.1 什么是JSONP

JSONP (JSON with Padding or JSON-P) is a JSON extension used by web
developers to overcome the cross-domain restrictions imposed by
browsers’ same-origin policy that limits access to resources retrieved
from origins other than the one the page was served by. In layman’s
terms, one website cannot just simply access the data from another
website.

It was developed because handling a browsers’ same origin policy can
be difficult, so using JSONP abstracts the difficulties and makes it
easier.

JSON stands for “JavaScript Object Notation”, a format by which
object fields are represented as key-value pairs which is used to
represent data.

JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题。其原理是根据 XmlHttpRequest
对象受到同源策略的影响,而 <script> 标签元素却不受同源策略影响,可以加载跨域服务器上的脚本,网页可以从其他来源动态产生
JSON 资料。用 JSONP 获取的不是 JSON 数据,而是可以直接运行的 JavaScript 语句。

2.2 使用 jQuery 集成的 $.ajax 实现 JSONP 跨域调用

我们先从简单的实现开始,利用 jQuery 中的 $.ajax 来实现上诉的跨域调用。

依然是上面的例子,我们将 服务器 3000 上的请求页面的 JavaScript 代码改为:


  1. // 回调函数 
  2.  
  3. function jsonpCallback(data) { 
  4.  
  5.     console.log("jsonpCallback: " + data.name) 
  6.  
  7.  
  8. $("#submit").click(function() { 
  9.  
  10.     var data = { 
  11.  
  12.         name: $("#name").val(), 
  13.  
  14.         id: $("#id").val() 
  15.  
  16.     }; 
  17.  
  18.     $.ajax({ 
  19.  
  20.         url: 'http://localhost:3001/ajax/deal', 
  21.  
  22.         data: data, 
  23.  
  24.         dataType: 'jsonp', 
  25.  
  26.         cache: false, 
  27.  
  28.         timeout: 5000, 
  29.  
  30.         // jsonp 字段含义为服务器通过什么字段获取回调函数的名称 
  31.  
  32.         jsonp: 'callback', 
  33.  
  34.         // 声明本地回调函数的名称,jquery 默认随机生成一个函数名称 
  35.  
  36.         jsonpCallback: 'jsonpCallback', 
  37.  
  38.         success: function(data) { 
  39.  
  40.             console.log("ajax success callback: " + data.name) 
  41.  
  42.         }, 
  43.  
  44.         error: function(jqXHR, textStatus, errorThrown) { 
  45.  
  46.             console.log(textStatus + ' ' + errorThrown); 
  47.  
  48.         } 
  49.  
  50.     }); 
  51.  
  52. });  

服务器 3001 上对应的处理函数为:


  1. app.get('/ajax/deal', function(req, res) { 
  2.  
  3.     console.log("server accept: ", req.query.name, req.query.id) 
  4.  
  5.     var data = "{" + "name:'" + req.query.name + " - server 3001 process'," + "id:'" + req.query.id + " - server 3001 process'" + "}" 
  6.  
  7.     var callback = req.query.callback 
  8.  
  9.     var jsonp = callback + '(' + data + ')' 
  10.  
  11.     console.log(jsonp) 
  12.  
  13.     res.send(jsonp) 
  14.  
  15.     res.end() 
  16.  
  17. })  

这里一定要注意 data 中字符串拼接,不能直接将 JSON 格式的 data 直接传给回调函数,否则会发生编译错误: parsererror Error: jsonpCallback was not called。

其实脑海里应该有一个概念:利用 JSONP 格式返回的值一段要立即执行的 JavaScript 代码,所以不会像 ajax 的 XmlHttpRequest 那样可以监听不同事件对数据进行不同处理。

处理结果如下所示:

2.3 使用 <script> 标签原生实现 JSONP

经过上面的事件,你是不是觉得 JSONP 的实现和 Ajax 大同小异?

其实,由于实现的原理不同,由 JSONP 实现的跨域调用不是通过 XmlHttpRequset 对象,而是通过 script
标签,所以在实现原理上,JSONP 和 Ajax 已经一点关系都没有了。看上去形式相似只是由于 jQuery 对 JSONP 做了封装和转换。

比如在上面的例子中,我们假设要传输的数据 data 格式如下:


  1.  
  2. name: "chiaki", 
  3.  
  4. id": "3001" 
  5.  
  6. }  

那么数据是如何传输的呢?HTTP 请求头的第一行如下:


  1. GET /ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032 HTTP/1.1 

可见,即使形式上是用 POST 传输一个 JSON 格式的数据,其实发送请求时还是转换成 GET 请求。

其实如果理解 JSONP 的原理的话就不难理解为什么只能使用 GET 请求方法了。由于是通过 script 标签进行请求,所以上述传输过程根本上是以下的形式:


  1. <script src = 'http://localhost:3001/ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script> 

这样从服务器返回的代码就可以直接在这个 script 标签中运行了。下面我们自己实现一个 JSONP:

服务器 3000请求页面的 JavaScript 代码中,只有回调函数 jsonpCallback:


  1. function jsonpCallback(data) { 
  2.  
  3.     console.log("jsonpCallback: "+data.name) 
  4.  
  5. }  

服务器 3000请求页面还包含一个 script 标签:


  1. <script src = 'http://localhost:3001/jsonServerResponse?jsonp=jsonpCallback'></script> 

服务器 3001上对应的处理函数:


  1. app.get('/jsonServerResponse', function(req, res) { 
  2.  
  3.     var cb = req.query.jsonp 
  4.  
  5.     console.log(cb) 
  6.  
  7.     var data = 'var data = {' + 'name: $("#name").val() + " - server 3001 jsonp process",' + 'id: $("#id").val() + " - server 3001 jsonp process"' + '};' 
  8.  
  9.     var debug = 'console.log(data);' 
  10.  
  11.     var callback = '$("#submit").click(function() {' + data + cb + '(data);' + debug + '});' 
  12.  
  13.     res.send(callback) 
  14.  
  15.     res.end() 
  16.  
  17. })  

与上面一样,我们在所获取的参数后面加上 “ – server 3001 jsonp process” 代表服务器对数据的操作。从代码中我么可以看到,处理函数除了根据参数做相应的处理,更多的也是进行字符串的拼接。

最终的结果为:

2.4 JSONP 总结

至此,我们了解了 JSONP 的原理以及实现方式,它帮我们实现前端跨域请求,但是在实践的过程中,我们还是可以发现它的不足:

只能使用 GET 方法发起请求,这是由于 script 标签自身的限制决定的。

不能很好的发现错误,并进行处理。与 Ajax 对比,由于不是通过 XmlHttpRequest 进行传输,所以不能注册 success、 error 等事件监听函数。

三、 使用 CORS 实现跨域调用

3.1 什么是 CORS?

Cross-Origin Resource Sharing(CORS)跨域资源共享是一份浏览器技术的规范,提供了 Web
服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET
要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比
JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。

3.2 CORS 的实现

还是以 服务器 3000 上的请求页面向 服务器 3001 发送请求为例。

服务器 3000 上的请求页面 JavaScript 不变,如下:


  1. $(function() { 
  2.  
  3.     $("#submit").click(function() { 
  4.  
  5.         var data = { 
  6.  
  7.             name: $("#name").val(), 
  8.  
  9.             id: $("#id").val() 
  10.  
  11.         }; 
  12.  
  13.         $.ajax({ 
  14.  
  15.             type: 'POST', 
  16.  
  17.             data: data, 
  18.  
  19.             url: 'http://localhost:3001/cors', 
  20.  
  21.             dataType: 'json', 
  22.  
  23.             cache: false, 
  24.  
  25.             timeout: 5000, 
  26.  
  27.             success: function(data) { 
  28.  
  29.                 console.log(data) 
  30.  
  31.             }, 
  32.  
  33.             error: function(jqXHR, textStatus, errorThrown) { 
  34.  
  35.                 console.log('error ' + textStatus + ' ' + errorThrown); 
  36.  
  37.             } 
  38.  
  39.         }); 
  40.  
  41.     }); 
  42.  
  43. });  

服务器 3001上对应的处理函数:


  1. app.post('/cors', function(req, res) { 
  2.  
  3.     res.header("Access-Control-Allow-Origin", "*"); 
  4.  
  5.     res.header("Access-Control-Allow-Headers", "X-Requested-With"); 
  6.  
  7.     res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); 
  8.  
  9.     res.header("X-Powered-By", ' 3.2.1') 
  10.  
  11.     res.header("Content-Type", "application/json;charset=utf-8"); 
  12.  
  13.     var data = { 
  14.  
  15.         name: req.body.name + ' - server 3001 cors process', 
  16.  
  17.         id: req.body.id + ' - server 3001 cors process' 
  18.  
  19.     } 
  20.  
  21.     console.log(data) 
  22.  
  23.     res.send(data) 
  24.  
  25.     res.end() 
  26.  
  27. })  

在服务器中对返回信息的请求头进行了设置。

最终的结果为:

3.3 CORS 中属性的分析

  • Access-Control-Allow-Origin

The origin parameter specifies a URI that
may access the resource. The browser must enforce this. For requests
without credentials, the server may specify “*” as a wildcard, thereby
allowing any origin to access the resource.

  • Access-Control-Allow-Methods

Specifies the method or methods allowed
when accessing the resource. This is used in response to a preflight
request. The conditions under which a request is preflighted are
discussed above.

  • Access-Control-Allow-Headers

Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

3.4 CORS 与 JSONP 的对比

CORS 除了 GET 方法外,也支持其它的 HTTP 请求方法如 POST、 PUT 等。

CORS 可以使用 XmlHttpRequest 进行传输,所以它的错误处理方式比 JSONP 好。

JSONP 可以在不支持 CORS 的老旧浏览器上运作。

四、 一些其它的跨域调用方式

4.1 window.name

window对象有个name属性,该属性有个特征:即在一个窗口 (window) 的生命周期内,窗口载入的所有的页面都是共享一个
window.name 的,每个页面对 window.name 都有读写的权限,window.name
是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。

4.2 window.postMessage()

这个方法是 HTML5 的一个新特性,可以用来向其他所有的 window 对象发送消息。需要注意的是我们必须要保证所有的脚本执行完才发送 MessageEvent,如果在函数执行的过程中调用了他,就会让后面的函数超时无法执行。

作者:佚名

来源:51CTO

时间: 2024-08-31 17:24:13

前端跨域请求原理及实践的相关文章

JQuery的Ajax跨域请求原理概述及实例_jquery

今天在项目中需要做远程数据加载并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究,发 JQuery对于Ajax的跨域请求有两类解决方案,不过都是只支持get方式.分别是JQuery的 jquery.ajax jsonp格式和jquery.getScript方式. 什么是jsonp格式呢?API原文:如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型.

jquery的ajax跨域请求原理和示例_jquery

今天在项目中需要做远程数据加载并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究,发 JQuery对于Ajax的跨域请求有两类解决方案,不过都是只支持get方式.分别是JQuery的 jquery.ajax jsonp格式和jquery.getScript方式. 什么是jsonp格式呢?API原文:如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型.

解决前端跨域问题方案汇总_javascript技巧

1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.js http://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.js http://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.js http://www.a.com/b.js 同一域名,不同端口 不允许 http://www.a.com/a.js https://www.a.com/b

Ajax如何进行跨域请求?Ajax跨域请求的原理

本文实例为大家分享了Ajax跨域请求的具体实现过程,供大家参考,具体内容如下 下面我们在本地建两个站点演示一下 第一步首先我们在本地搭建好一个Apache服务器:下载地址: 第二步服务器配置好以后,在本地配置好两个虚拟的域名: 第三步我们在C盘建一个文件夹命名为"HTML5": 第四步找到Apache虚拟主机的配置文件,然后打开配置文件 第五步在第三步建的HTML5文件夹下分别建一个文件夹a和文件夹b; 第六步修改Apache虚拟主机的配置文件,如图 第七步修改一下host文件,添加a

JSONP跨域的原理解析及其实现介绍

 JSONP跨域GET请求是一个常用的解决方案,下面我们来看一下JSONP跨域是如何实现的,并且探讨下JSONP跨域的原理 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容.    JavaScript这个安全策略在进行多if

Ajax跨域请求 JSON JSONP

同源策略和跨域-总结 目录: 1.同源策略 2.跨域 3.几种跨域技术   1.同源策略 什么叫同源? URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源.相反,只要协议,域名,端口有任何一个的不同,就被当作是跨域. e.g. 对于http://store.company.com/dir/page.html进行同源检测: URL 结果 原因 http://store.company.com/dir2/other.html 成功 仅路径不同 http://st

[IT]JSONP跨域的原理解析

JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript 只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进行多iframe或多窗口编程.以及Ajax编程时显得尤为重要.根据这个策略,在baidu.com下的页面中包含的JavaScript代码

JSONP跨域的原理解析及其实现介绍_javascript技巧

JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进行多iframe或多窗口编程.以及Ajax编程时显得尤为重要.根据这个策略,在baidu.com下的页面中包含的JavaScript代码,

探讨跨域请求资源的几种方式

什么是跨域 JSONP proxy代理 cors xdr 由于浏览器同源策略,凡是发送请求url的协议.域名.端口三者之间任意一与当前页面地址不同即为跨域.具体可以查看下表(来源) JSONP 这种方式主要是通过动态插入一个script标签.浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下). <script> var _script = document.createElement('script'); _script.type = "t