如今,在开发联合调试的过程中,需要跨域获取数据,因为使用jquery,当然使用datatype :‘jsonp’就可以轻松解决。但是当时后端不支持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内容:
复制代码如下: alert(' hello ');
然后写a.com/a.html:
复制代码的代码如下: script type=' text/JavaScript ' src=' 3358b.com/b.js'.
跑a.html,结果显而易见。你好肯定会出现。
指南步骤2
修改b.com/b.js文件的内容:
复制代码如下: yfunction(' hello ');
然后修改a.com/a.html:
脚本类型=' text/JavaScript ' src=' http://b.com/b.js'脚本函数my function(str){//定义处理数据的函数alert(str ' world ');}/脚本运行a.html,弹出“你好世界”。这应该是毫无疑问的。
指南步骤3
让我们看看上面的第2步。b.js中的“你好”是b.js域名下的数据,可以在a.com/a.html.显示,不是已经实现跨域数据请求了吗?
此外,因为脚本标记中的src不一定指向js文件,所以它可以指向任何地址。
因此,我们可以在上面的步骤2中更改a.html的内容:脚本类型=' text/JavaScript ' src=' http://b.com/b.js',我们可以将b.js更改为b.html或b.json等。执行可以正常返回。
指南步骤4
以上数据是静态的,写在文件里,不能满足我们的需求。因为我们的ajax请求数据实时变化,所以我们需要使数据动态化。
我们可以让脚本表调用一个动态页面(接口)来获取动态数据,这里我们想到的是回调函数。
编辑a.com/a.html页面内容:
脚本类型=' text/JavaScript ' src=' http://b.com/b . aspx?callback=my function ' script function my function(str){//定义处理数据的函数alert(str ' world ');}/我们添加的脚本?Callback=myFunction,表示显示数据的函数也是动态传入的。
使用jsonp方法获取数据的另一个要点是后端接口也必须支持jsonp。例如,下面的代码是将返回的数据转换成jsonp格式。请继续阅读:(。net语言在这里被用作例子)。
受保护的void page_load(对象发送者,EventArgs e){ if(this。IsPostBack==false){字符串回调=' ';if(请求['回调']!=null){回调=请求['回调'];字符串数据=' hello回应。Write(回调'(' data ')');//界面页面返回的数据格式为“函数(参数)”格式。} }}
代码的意思很简单,就是获取调用函数的参数。如果你在这里叫b.aspx?如果回调=myFunction,将返回myFunction('hello ')。如果后端代码为数据分配了一个变量,这里的“hello”将变成动态数据。
指南步骤5
看上面的步骤,虽然获取的数据是动态的,但是在页面中引入脚本标签只能执行一次,获取一次,显然不能满足要求。因此,在必要的时候,我们必须动态地添加这样的脚本标签一次。
所以我们需要在这里封装一个函数:
函数addScript(src){ var script=document . createelement(' script ');script.setAttribute('type ',' text/JavaScript ');script.src=srcdocument.body.appendChild(脚本);}当您需要呼叫时,请前往并执行:
addScript('b.com/b.aspx?callback=my FuncTion’);函数myFunction(数据){//定义了处理数据的函数alert(数据);}好了,上面的过程就是jsonp的原理,所以我们不用去记那些混淆的定义,只需要看这个过程一次,相信就能明白它的本质。
Jquery实现跨域。
Jquery跨域方法。
$.Ajax({ URL : ' b.com/b.json',//different域类型: 'GET ',//jsonp模式,只有GET是合法的,dataType: 'jsonp ',///数据类型jsonp: 'callback ',//指定回调函数名,与服务器收到的一致,返回成功:函数(数据){console.log(数据);}})使用jquery非常方便,那么它是如何实现这种转换的呢?让我们看看jquery源代码的这一部分。
Jq实现jsonp源代码分析。
我贴出了jquery的源代码分析来实现jsonp:
If (s.dataType=='jsonp') {//构建jsonp请求的字符集字符串。Jsonp是跨域请求,回调=?将添加函数名if (type=='GET') {//使GET的url包含回调=?函数名if(!s . URL . match(jsre))s . URL=(s . URL . match(/?/) ?'' : '?')(s.jsonp ||“回调”)“=?”;}//构建新的s.data以包含回调=函数名else if(!s.data ||!s . data . match(jsre))s . data=(s . data?s.data '' : '') (s.jsonp || '回调')'=?';s . DataType=“JSON”;}//判断是否是jsonp,如果是,处理。if(s . DataType==' JSON '(s . data s . data . match(jsre)| | s . URL . match(jsre))){ jsonp=' jsonp ' JSC;//如果(s.data) s.data=(s.data ' '),则添加回调函数名。将(jsre,'=' jsonp' $1 ')替换为字符集字符串的回调=;s.url=s.url.replace(jsre,'=' jsonp ' $ 1 ');//我们需要确保jsonp类型的响应能够正确执行。JSONP的类型必须是脚本。只有这样才能执行服务器返回的//代码。这是这里调用的回调函数。s.dataType=“脚本”;//在window下注册一个jsonp回调函数,让ajax request返回的代码调用并执行。window[jsonp]=function(tmp){ data=tmp;成功();完成();//垃圾收集,释放变量,删除jsonp对象,去掉头中添加的脚本元素窗口[jsonp]=undefined;尝试{删除窗口[jsonp];} catch(e){ } if(head)head . remove child(script);};}if (s.data type=='GET') {//数据有效,并且追加到get type s.url=(s.url.match(/?/) ?'' : '?')s . data;//防止IE重复发送get和post数据s.data=null} if(s . DataType==' script ' type==' GET ' parts(parts[1]parts[1]!=location.protocol || parts[2]!=location.host)) {//将脚本src=' http 3360 '/脚本var head=document . getelementsbytagname(' head ')[0]添加到head;var script=document . createelement(' script ');script . src=s . URL;if(s . script charset)script . charset=s . script charset;if(!Jsonp) {//如果数据类型不是Jsonp,但url是跨域的。使用scriptr的onload或onreadystatechange事件来触发回调函数。var done=false//添加处理器脚本. onload=script . onreadystatechange=function(){ if(!完成(!this . readystate | | this . readystate==' loaded ' | | this . readystate==' complete '){ done=true;成功();完成();head.removeChild(脚本);} };} head.appendChild(脚本);//脚本元素注入已经被用来处理一切。返回未定义;}上面的代码有点复杂,但我们只需挑选重要的代码并查看它们。
我们来分析一下这个过程。事实上,这个过程就是我上面问题的答案:
执行完这里的代码,其实就是判断是否配置了datatype :‘jsonp’。如果是jsonp协议,应该在url中加入Callback=jqueryxx(函数名),jQuery会将url转换成:http://b.com/b.json? Callback=jqueryxx,然后在html中插入。加载文件b.json后,将执行回调函数jQueryxxx。此时这个函数中已经存在动态数据(json格式的数据),在页面上执行时可以随意处理数据,但别忘了后端还必须支持jsonp格式。从而实现跨域数据采集的功能。
本机js包jsonp。
函数jsonp(config){ var options=config | | { };//需要配置URL、成功、时间、失败四个属性:var回调名称=('jsonp _' math.random())。替换('.','');var Ohead=document . GetElementsBytagname(' head ')[0];var oScript=document . create element(' script ');ohead . appendchild(oScript);window[回调名]=函数(JSON){//创建jsonp回调函数Ohead . remove child(Oscript);clear time out(Oscript . timer);window[callbackName]=null;options . success options . success(JSON);//先删除脚本标签,但实际执行的是成功函数};oScript.src=options.url '?'callbackName//发送请求if (options.time) {//设置超时处理脚本。timer=settimeout(function(){ window[callback name]=null;ohead . remove child(Oscript);options . fail options . fail({ message : ' time out ' });},options . time);} };
这是我自己编写的实现jsonp获取跨域数据的方法。
我们只需要调用jsonp函数就可以跨域获取数据。例如:
Jsonp ({url:'/b.com/b.json ',success3360函数(d){//数据处理},time: 5000,fail3360函数(){//错误处理}})总结及注意事项:
使用jsonp方法时,被调用的接口只能在控制台的network-JS中找到,不再是XHR类。由于页面呈现时脚本只执行一次,动态数据需要多次调用,插入使用后需要删除,需要初始化回调函数。当实现本机js时,最好添加一个请求超时函数,以便于调试。
总之,jsonp是一种获取跨域json数据的方法。