首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议140:正确理解JSONP异步通信协议

关灯直达底部

浏览器安全模型规定:XMLHttpRequest和框架(frame)等只能够在同一个域内进行异步通信。受同源策略的限制,不能够使用Ajax或框架实现跨域(即与外部服务器)通信。从安全角度考虑,这个规定很合理,不过也会给分布式Web开发带来麻烦。而JSONP是一种可以绕过同源策略的方法,从任何服务器端直接返回可执行的JavaScript函数调用(即回调函数)或JavaScript对象(JSON格式数据)。

JSONP是JSON with Padding的简称,它能够通过在当前文档(客户端)中生成脚本(即<script>标签)来调用跨域脚本(服务器端脚本文件),这是一个非官方的协议。

JSONP允许在服务器端集成Script Tags(脚本标记,即服务器动态生成的JavaScript脚本字符串)并把这些脚本标记返回到客户端,通过JavaScript Callback(JavaScript回调函数)的形式实现跨域访问。当然,这仅仅是JSONP简单的实现形式。现在的一些JavaScript技术框架都在使用JSONP实现跨域异步通信,如dojo、JQuery、Google Social Graph API、Digg API、GeoNames webservice、豆瓣API、Del.icio.us JSON API等。下面通过一个示例介绍如何通过JSONP约定来实现跨域异步信息交互。

第1步,在客户端调用提供JSONP支持的URL Service(URL服务),获取JSONP格式数据。所谓JSONP支持的URL Service,就是在请求的URL中必须附加在客户端的可以回调的函数,并且按约定正确设置回调函数参数,默认参数名为jsonp,偶尔也会见到以“callback”为参数名传送回调函数名的情况。总之,只要服务器能够识别即可。例如,定义URL Service为:


http://localhost/mysite/serve.ASP?jsonp=callback&d=1


其中参数jsonp的值为约定的回调函数名。JSONP格式的数据就是把JSON数据作为参数传递给回调函数并传回。如果响应的JSON数据为:


{

/"title/":/"JSONP Test/",

/"link/":/"http://www.jscode.cn//",

/"modified/":/"2012-4-1/",

/"items/":{

/"id/":1,

/"title/":/"百度/",

/"link/":/"http://www.baidu.com//",

/"description/":/"百度一下,你就知道/"

}

}


那么真正返回到客户端的Script Tags(脚本标记)如下,即所谓的JSONP格式数据。


callback({

/"title/":/"JSONP Test/",

/"link/":/"http://www.jscode.cn//",

/"modified/":/"2012-4-1/",

/"items/":{

/"id/":1,

/"title/":/"百度/",

/"link/":/"http://www.baidu.com//",

/"description/":/"百度一下,你就知道/"

}

})


第2步,在客户端向服务器端发出URL Service请求且服务器接到请求之后,应该完成两件事情:一是接收并处理参数信息,特别是要获取回调函数名;二是根据参数信息生成符合客户端需要的Script Tags(脚本标记)字符串,并且把这些字符串响应给客户端。例如,服务器端的处理脚本文件如下:


<%@LANGUAGE=/"VBSCRIPT/"CODEPAGE=/"65001/"%>

<%

callback=Request.QueryString(/"jsonp/")//接收回调函数名的参数值

id=Request.QueryString(/"id/")//接收响应信息的编号

Response.AddHeader/"Content-Type/",/"text/html;charset=utf-8/"//设置响应信息的字符编码为uft-8

Response.Write(callback&/"(/")//输出回调函数名,开始生成Script Tags字符串

%>

{

/"title/":/"JSONP Test/",

/"link/":/"http://www.jscode.cn//",

/"modified/":/"2012-4-1/",

/"items/":

<%

ifthen//如果id参数值为1,则输出下面的对象信息

%>

{

/"title/":/"百度/",

/"link/":/"http://www.baidu.com//",

/"description/":/"百度一下,你就知道/"

}

<%

elseifthen//如果id参数值为2,则输出下面的对象信息

%>

{

/"title/":/"搜狗/",

/"link/":/"http://www.sogou.com//",

/"description/":/"上网从搜狗开始/"

}

<%

else//否则输出空信息

Response.Write(/"/")

end if//结束条件语句

Response.Write(/"))/")//封闭回调函数,输出Script Tags字符串

%>


包含在“<%”和“%>”分隔符之间的代码是ASP处理脚本。在该分隔符之后的是输出到客户端的普通字符串。在ASP脚本中,使用Response.Write方法输出回调函数名和运算符号。其中还用条件语句来判断从客户端传递过来的参数值,并根据参数值决定响应的具体信息。

第3步,在客户端设计回调函数。设计回调函数应该根据具体的应用项目,以及返回的JSONP数据进行处理。例如,针对上面返回的JSONP数据,把其中的数据列表显示出来,代码如下:


function callback(info){

var temp=/"/";

for(var i in info){

if(typeof info[i]!=/"object/"){

temp+=i+/"=/"/"+info[i]+/"/"<br/>/";

}

else if((typeof info[i]==/"object/")){

temp+=/"<br/>/"+i+/"=/"+/"{<br/>/";

var o=info[i];

for(var j in o){

temp+=/"    /"+j+/"=/"/"+o[j]+/"/"<br/>/";

}

temp+=/"}/";

}

}

var p=document.getElementById(/"test/");

p.innerHTML=temp;

}


第4步,设计客户端交互页面与信息展示。这一步比较简单,可以在页面中插入一个<p>标签,然后把输出的信息插入到该元素中。同时为页面设计一个交互按钮,单击该按钮将触发请求函数,并且向服务器端发出URL Service请求。响应完毕,在Script Tags字符串被传回到客户端之后,将调用回调函数对响应的数据进行处理和显示。


<p></p>