今天在开发联调的过程中,需要跨域的获取数据,因为使用的jquery,当然使用dataType:'jsonp'就能够很easy的解决了。
但是因为当时后端没有支持jsonp来访问,后来他在实现这个功能的时候问了我一句,jsonp形式返回的格式是怎么样子的?我一直以来只知道怎么使用,迷迷糊糊的却没有答上来。。。
虽然后来解决了,但是对于喜欢解决问题的我,心里却一直耿耿于怀,必须得把这个研究透彻了,于是我开始翻阅资料,看到后面真有种豁然开朗的感觉,于是打算做个笔记与大家分享。
JSON和JSONP的区别
JSON和JSONP虽然只有一个字母的差别,但其实他们根本不是一回事儿:JSON是一种数据交换格式,而JSONP是一种跨域数据交互的协议,使用JSONP方法获取到的仍然是json格式的数据。
说白了,用JSON来传数据,靠JSONP来跨域
。
JSONP详细阐述
我们都知道,一个页面的ajax只能获取和此页面同域的数据。
,所以当我们需要跨域获取数据的时候就需要使用到JSONP方法来获取了。
如下图所示,就是使用json格式获取跨域数据返回的错误提示:
那么该如何解决呢?使用框架的前端童鞋们可能都有自己相应的办法,比如jquery就是把dataType设为jsonp
就能解决了,但是我们在使用的时候有没有想过,为什么这样就能解决呢?中心思想又是什么呢?
下面就开始为大家详细阐述,首要思想就是利用scirpt标签来引入跨域的数据。我们从最开始慢慢来深入jsonp的过程。
引导步骤1
编写b.com/b.js
内容:
然后编写a.com/a.html
内容:
运行a.html,结果很明显,肯定会弹出hello。
引导步骤2
修改b.com/b.js
文件内容:
然后修改a.com/a.html
内容:
<script type='text/javascript' src='http://b.com/b.js'> <script> function myFunction(str) { //定义处理数据的函数 alert(str + ' world'); } </script>
运行a.html 结果是弹出‘hello world'。这个应该也毫无疑问。
引导步骤3
让我们再看一下上面的步骤2,b.js中的‘hello'就是b.com域名下的数据了,而能够在a.com/a.html中执行显示出来,这不就已经实现了跨域请求数据了
吗?
另外,因为script标签中的src 不一定要指向js文件,而可以指向任何地址。
所以,我们把上面步骤2中a.html的内容:<script type="text/javascript" src="http://b.com/b.js"></script>
,我们把其中的b.js
改成b.html
或者b.json
等等都是可以的,执行都能正常返回。
引导步骤4
上面的数据都是静态的,是在文件内写死的,所以并不能满足我们的需求了吧。。。因为我们ajax请求数据是实时变化的,所以我们要把数据变成动态的了。
我们可以让script表器去调用一个动态的页面(接口),去实现获取动态数据,这里就想到了回调函数
.
编辑a.com/a.html
页面内容:
<script type='text/javascript' src='http://b.com/b.aspx?callback=myFunction'> <script> function myFunction(str){ //定义处理数据的函数 alert(str + ' world'); } </script>
我们在src引用地址中加了?callback=myFunction
,意思是把显示数据的函数也动态的传入了。
使用jsonp方法获取数据,还有一个要点就是后端接口也要支持jsonp才行
,比如下面一段代码就是让返回的数据变成jsonp的格式,请继续看:(此处使用.net语言作为例子)
protected void page_load(object sender, EventArgs e){ if(this.IsPostBack == false){ string callback = ''; if(Request["callback"] != null){ callback = request["callback"]; string data = "hello"; Response.Write(callback+"("+ data + ")"); //接口页面返回的数据格式“函数(参数)”的格式。 } } }
代码的意思很简单,就是获取调用函数的参数。如果这里调用b.aspx?callback=myFunction
的话,则会返回myFunction('hello')
,如果后端代码给data赋值一个变量,这里的‘hello'则变成了动态的数据了。
引导步骤5
再看上面的步骤,虽然获取的数据是动态的了,但在页面上引入一个script标签,却只能执行一次,获取一次,显然还是不能满足需求的。所以我们在需要的时候,就得动态的添加一次这样的script标签。
所以我们在这里需要封装一个函数:
function addScript(src){ var script = document.createElement('script'); script.setAttribute('type','text/javascript'); script.src= src; document.body.appendChild(script); }
需要调用的时候,就去执行:
addScript('b.com/b.aspx?callback=myFunction'); function myFunction(data){//定义处理数据的函数 alert(data); }
ok,上面的过程就是jsonp的原理,我们不必去记住那些令人纠结不清的定义,只要看一遍这个过程,我相信就能明白其中的精髓了吧。
jquery实现跨域
jquery跨域方法
$.ajax({ url: 'b.com/b.json', //不同的域 type: 'GET', // jsonp模式只有GET是合法的 dataType: 'jsonp', // 数据类型 jsonp: 'callback', // 指定回调函数名,与服务器端接收的一致,并回传回来 success: function(data) { console.log(data); } })
使用jquery非常方便,那么它是怎么实现这个转化的呢?下面我们来看看这部分的jquery源码。
jq实现jsonp源码分析
我贴出网上给的jquery实现jsonp部分的源码分析:
if (s.dataType == "jsonp") { // 构建jsonp请求字符集串。jsonp是跨域请求,要加上callback=?后面将会加函数名 if (type == "GET") { //使get的url包含 callback=?后面将 会进行加函数名 if (!s.url.match(jsre)) s.url += (s.url.match(/?/) ? "&" : "?") + (s.jsonp || "callback") + "=?"; } // 构建新的s.data,使其包含 callback=function name else if (!s.data || !s.data.match(jsre)) s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?"; s.dataType = "json"; } //判断是否为jsonp,如果是 ,进行处理。 if (s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre))) { jsonp = "jsonp" + jsc ++; //为请 求字符集串的callback=加上生成回调函数名 if (s.data) s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1"); s.url = s.url.replace(jsre, "=" + jsonp + "$1"); // 我们需要保证jsonp 类 型响应能正确地执行 //jsonp的类型必须为script。这样才能执行服 务器返回的 //代码。这里就是调用这个回调函数。 s.dataType = "script"; //window下注册一个jsonp回调函数 有,让ajax请求返回的代码调用执行它, window[jsonp] = function(tmp) { data = tmp; success(); complete(); // 垃圾回收,释放联变量,删除jsonp的对象,除去head中加的script元素 window[jsonp] = undefined; try { delete window[jsonp]; } catch (e) {} if (head) head.removeChild(script); }; } if (s.data && type == "GET") { // data有效,追加到get类型的url上去 s.url += (s.url.match(/?/) ? "&" : "?") + s.data; // 防止IE会重复发送get和post data s.data = null; } if (s.dataType == "script" && type == "GET" && parts && (parts[1] && parts[1] != location.protocol || parts[2] != location.host)) { // 在head中加上<script src=""></script> var head = document.getElementsByTagName("head")[0]; var script = document.createElement("script"); script.src = s.url; if (s.scriptCharset) script.charset = s.scriptCharset; if (!jsonp) { //如果datatype不是jsonp,但是url却是跨域 的。采用scriptr的onload或onreadystatechange事件来触发回 调函数。 var done = false; // 对所有浏览器都加上处理器 script.onload = script.onreadystatechange = function() { if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) { done = true; success(); complete(); head.removeChild(script); } }; } head.appendChild(script); // 已经使用 了script 元素注射来处理所有的事情 return undefined; }
上面的代码稍显复杂,但是我们挑拣重要的看就好了。
我们来分析一下这个过程,其实这个过程也就是上面我提出问题的答案
了:
这里执行代码之后,其实就是判断是否配置了dataType: 'jsonp',如果是jsonp协议,则要在url上加callback=jQueryxxx(函数名),jquery会把url转化为:http://b.com/b.json?callback=jQueryxxx
,然后再在html中插入,加载完b.json这个文件后,就会执行jQueryxxx这个回调函数,而且此时这个函数里面已经存在了动态数据(json格式数据),所以在页面上执行的时候就能够随心所欲的处理数据了,但是也别忘了后端也要支持jsonp格式才行。所以这样就达到了跨域获取数据的功能。
原生js封装jsonp
function jsonp(config) { var options = config || {}; // 需要配置url, success, time, fail四个属性 var callbackName = ('jsonp_' + Math.random()).replace(".", ""); var oHead = document.getElementsByTagName('head')[0]; var oScript = document.createElement('script'); oHead.appendChild(oScript); window[callbackName] = function(json) { //创建jsonp回调函数 oHead.removeChild(oScript); clearTimeout(oScript.timer); window[callbackName] = null; options.success && options.success(json); //先删除script标签,实际上执行的是success函数 }; oScript.src = options.url + '?' + callbackName; //发送请求 if (options.time) { //设置超时处理 oScript.timer = setTimeout(function () { window[callbackName] = null; oHead.removeChild(oScript); options.fail && options.fail({ message: "超时" }); }, options.time); } };
这是我自己写的一个原生js实现jsonp获取跨域数据的方法。
我们只需要调用jsonp函数就能够跨域获取数据了。比如:
jsonp({ url: '/b.com/b.json', success: function(d){ //数据处理 }, time: 5000, fail: function(){ //错误处理 } })小结
再说几点注意的地方:
使用jsonp方法时,在控制台的network-JS
中才能找到调用的接口,不再是XHR类了。由于页面渲染的时候script只执行一次,而且动态数据需要多次调用,所以在插入使用之后需要删除,并且要初始化回调函数。原生js实现时,最好加一个请求超时的功能,方便调试。
总之jsonp就是一种获取跨域json数据的方法。

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

因此,在这里,您准备好了解所有称为Ajax的东西。但是,到底是什么? AJAX一词是指用于创建动态,交互式Web内容的一系列宽松的技术。 Ajax一词,最初由Jesse J创造

10款趣味横生的jQuery游戏插件,让您的网站更具吸引力,提升用户粘性!虽然Flash仍然是开发休闲网页游戏的最佳软件,但jQuery也能创造出令人惊喜的效果,虽然无法与纯动作Flash游戏媲美,但在某些情况下,您也能在浏览器中获得意想不到的乐趣。 jQuery井字棋游戏 游戏编程的“Hello world”,现在有了jQuery版本。 源码 jQuery疯狂填词游戏 这是一个填空游戏,由于不知道单词的上下文,可能会产生一些古怪的结果。 源码 jQuery扫雷游戏

本教程演示了如何使用jQuery创建迷人的视差背景效果。 我们将构建一个带有分层图像的标题横幅,从而创造出令人惊叹的视觉深度。 更新的插件可与JQuery 1.6.4及更高版本一起使用。 下载

本文讨论了在浏览器中优化JavaScript性能的策略,重点是减少执行时间并最大程度地减少对页面负载速度的影响。

Matter.js是一个用JavaScript编写的2D刚体物理引擎。此库可以帮助您轻松地在浏览器中模拟2D物理。它提供了许多功能,例如创建刚体并为其分配质量、面积或密度等物理属性的能力。您还可以模拟不同类型的碰撞和力,例如重力摩擦力。 Matter.js支持所有主流浏览器。此外,它也适用于移动设备,因为它可以检测触摸并具有响应能力。所有这些功能都使其值得您投入时间学习如何使用该引擎,因为这样您就可以轻松创建基于物理的2D游戏或模拟。在本教程中,我将介绍此库的基础知识,包括其安装和用法,并提供一

本文演示了如何使用jQuery和ajax自动每5秒自动刷新DIV的内容。 该示例从RSS提要中获取并显示了最新的博客文章以及最后的刷新时间戳。 加载图像是选择


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Dreamweaver CS6
视觉化网页开发工具

WebStorm Mac版
好用的JavaScript开发工具