`
wbj0110
  • 浏览: 1602917 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

深入浅出JSONP:解决AJAX跨域问题(转)

阅读更多

取不到数据!

上周客户新买了服务器,原本在旧的服务器上放着客户的Web主页信息和一个后台程序(asp.net),在客户的主页中有一个动态显示最新消息的处理,这个处理就是通过ajax异步从那个后台程序中取得的。由于又购买了新的服务器,客户想把web主页和那个后台程序分开来,后台程序被部署到了新的服务器上。不过这个项目是我的同事小福同志开发的,也就由他来把程序分开部署,然后进行一些小改动。

"怎么最新消息取不到了,异步处理的url也已经添加上新服务器的地址(http://xxxx.com/.../news.ashx),奇怪了..."小福在一边抱怨,我看了看IE7下还出了个脚本错误"アクセスが拒否されました"的错误(环境是日文的,意思是访问被拒绝了)。网上查了下中文环境应该是"没有权限"吧。在Firefox和Chrome上是看不到任何脚本错误的,不过可以通过Firebug工具测出这个错误("Permission denied to call method XMLHttpRequest.open")。

同源策略

为什么会出这样的错误呢?这是因为所有支持Javascript的浏览器都会使用同源策略这个安全策略。看看百度的解释:

同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当一个百度浏览器执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。

这就是引起为何取不到数据的原因了,那如何才能解决跨域的问题呢?没错,我们现在可以进入正题,来了解下什么是JSONP了。

JSON和JSONP

JSONP和JSON好像啊,他们之间有什么联系吗?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。对于JSON大家应该是很了解了吧,不是很清楚的朋友可以去json.org上了解下,简单易懂。

JSONP是JSON with Padding的略称。它是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。--来源百度

JSONP就像是JSON+Padding一样(Padding这里我们理解为填充), 我们先看下面的小例子然后再详细介绍。

跨域的简单原理

光看定义还不是很明白,那首先我们先来手动做个简单易懂的小测试。新建一个asp.net的web程序,添加sample.html网页和一个test.js文件,代码如下:

sample.html的代码:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  2.  <html xmlns="http://www.w3.org/1999/xhtml" > 
  3.  <head> 
  4.      <title>test</title> 
  5.      <script type="text/javascript" src="test.js"></script> 
  6.  </head> 
  7.  <body> 
  8.  </body> 
  9.  </html> 

test.js的代码:

  1. alert("success"); 

打开sample.html后会跳出"success”这样的这样的信息框,这似乎并不能说明什么, 跨域问题到底怎么解决呢?好,现在我们模拟下非同源的环境,刚才我们不是已经用Visual Studio新建了一个Web程序吗(这里我们叫A程序),现在我们再打开一个新的Visual Studio再新建一个Web程序(B程序),将我们的之前的test.js文件从A程序中移除然后拷贝到B程序中。两个程序都运行起来后,Visual Studio会启动内置服务器,假设A程序是localhost:20001,B程序是localhost:20002,这就模拟了一个非同源的环境了(虽然域名相同但端口号不同,所以是非同源的)。

OK,我们接下来应该改下sample.html里的代码,因为test.js文件在B程序上了,url也就变成了localhost:20002。

sample.html部分代码:

  1. <script type="text/javascript" src="http://localhost:20002/test.js"></script> 

请保持AB两个Web程序的运行状态,当你再次刷新localhost:20001/sample.html的时候,和原来一样跳出了"success"的对话框,是的,成功访问到了非同源的localhost:20002/test.js这个所谓的远程服务了。到了这一步,相信大家应该已经大概明白如何跨域访问了的原理了。

<script>标签的src属性并不被同源策略所约束,所以可以获取任何服务器上脚本并执行。

JSONP的实现模式:CallBack

刚才的小例子讲解了跨域的原理,我们回上去再看看JSONP的定义说明中讲到了javascript callback的形式。那我们就来修改下代码,如何实现JSONP的javascript callback的形式。

程序A中sample的部分代码:

  1. <script type="text/javascript">  
  2.  //回调函数  
  3.  function callback(data) {  
  4.      alert(data.message);  
  5.  }  
  6.  </script>  
  7.  <script type="text/javascript" src="http://localhost:20002/test.js"></script> 

程序B中test.js的代码:

  1. //调用callback函数,并以json数据形式作为阐述传递,完成回调  
  2.  callback({message:"success"}); 

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义吧。

一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。

程序A中sample的部分代码:

  1. <script type="text/javascript">  
  2.      function callback(data) {  
  3.          alert(data.message);  
  4.      }  
  5.      //添加<script>标签的方法  
  6.      function addScriptTag(src){  
  7.      var script = document.createElement('script');  
  8.          script.setAttribute("type","text/javascript");  
  9.          script.src = src;  
  10.          document.body.appendChild(script);  
  11.      }  
  12.        
  13.      window.onload = function(){  
  14.          addScriptTag("http://localhost:20002/test.js");  
  15.      }  
  16.  </script> 

程序B的test.js代码不变,我们再执行下程序,是不是和原来的一样呢。如果我们再想调用一个远程服务的话,只要添加addScriptTag方法,传入远程服务的src值就可以了。这里说明下为什么要将addScriptTag方法放入到window.onload的方法里,原因是addScriptTag方法中有句document.body.appendChild(script);,这个script标签是被添加到body里的,由于我们写的javascript代码是在head标签中,document.body还没有初始化完毕呢,所以我们要通过window.onload方法先初始化页面,这样才不会出错。

上面的例子是最简单的JSONP的实现模型,不过它还算不上一个真正的JSONP服务。我们来看一下真正的JSONP服务是怎么样的,比如Google的ajax搜索接口:http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=?&callback=?

q=?这个问号是表示你要搜索的内容,最重要的是第二个callback=?这个是正如其名表示回调函数的名称,也就是将你自己在客户端定义的回调函数的函数名传送给服务端,服务端则会返回以你定义的回调函数名的方法,将获取的json数据传入这个方法完成回调。有点罗嗦了,还是看看实现代码吧:

  1. <script type="text/javascript">  
  2.      //添加<script>标签的方法  
  3.      function addScriptTag(src){  
  4.          var script = document.createElement('script');  
  5.          script.setAttribute("type","text/javascript");  
  6.          script.src = src;  
  7.          document.body.appendChild(script);  
  8.      }  
  9.        
  10.      window.onload = function(){  
  11.          //搜索apple,将自定义的回调函数名result传入callback参数中  
  12.          addScriptTag("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=apple&callback=result");  
  13.            
  14.      }  
  15.      //自定义的回调函数result  
  16.      function result(data) {  
  17.          //我们就简单的获取apple搜索结果的第一条记录中url数据  
  18.          alert(data.responseData.results[0].unescapedUrl);  
  19.      }  
  20.  </script> 

像这样的JSONP服务还有很多(以下信息来自使用 JSONP 实现跨域通信,第 1 部分: 结合 JSONP 和 jQuery 快速构建强大的 mashup):

Digg API:来自 Digg 的头条新闻:

http://services.digg.com/stories/top?appkey=http%3A%2F%2Fmashup.com&type=javascript&callback=?

Geonames API:邮编的位置信息:

http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=?

Flickr JSONP API:载入最新猫的图片:

http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?

Yahoo Local Search API:在邮编为 10504 的地区搜索比萨:

http://local.yahooapis.com/LocalSearchService/V3/localSearch?appid=YahooDemo&query=pizza&zip=10504&results=2&output=json&callback=?

接下来我们自己来创建一个简单的远程服务,实现和上面一样的JSONP服务。还是利用Web程序A和程序B来做演示,这次我们在程序B上创建一个MyService.ashx文件。

程序B的MyService.ashx代码:

  1. public class MyService : IHttpHandler  
  2.      {  
  3.          public void ProcessRequest(HttpContext context)  
  4.          {  
  5.              //获取回调函数名  
  6.              string callback = context.Request.QueryString["callback"];  
  7.              //json数据  
  8.              string json = "{\"name\":\"chopper\",\"sex\":\"man\"}";  
  9.    
  10.              context.Response.ContentType = "application/json";  
  11.              //输出:回调函数名(json数据)  
  12.              context.Response.Write(callback + "(" + json + ")");  
  13.          }  
  14.    
  15.          public bool IsReusable  
  16.          {  
  17.              get  
  18.              {  
  19.                  return false;  
  20.              }  
  21.          }  
  22.      } 

程序A的sample代码中的调用:

  1. <script type="text/javascript">  
  2.      function addScriptTag(src){  
  3.          var script = document.createElement('script');  
  4.          script.setAttribute("type","text/javascript");  
  5.          script.src = src;  
  6.          document.body.appendChild(script);  
  7.      }  
  8.        
  9.      window.onload = function(){  
  10.          //调用远程服务  
  11.          addScriptTag("http://localhost:20002/MyService.ashx?callback=person");  
  12.            
  13.      }  
  14.      //回调函数person  
  15.      function person(data) {  
  16.          alert(data.name + " is a " + data.sex);  
  17.      }  
  18.  </script> 

这就完成了一个最基本的JSONP服务调用了,是不是很简单,下面我们来了解下JQuery是如何调用JSONP的。

jQuery对JSONP的实现

jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法(详细可以参考http://api.jquery.com/jQuery.getJSON/)。那我们就来修改下程序A的代码,改用jQuery的getJSON方法来实现(下面的例子没用用到向服务传参,所以只写了getJSON(url,[callback])):

  1. <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>  
  2. <script type="text/javascript">  
  3.     $.getJSON("http://localhost:20002/MyService.ashx?callback=?",function(data){  
  4.         alert(data.name + " is a a" + data.sex);  
  5.     });  
  6. </script> 

结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个问号是内部自动生成的一个回调函数名。这个函数名大家可以debug一下看看,比如jQuery17207481773362960666_1332575486681。

当然,加入说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现(参数较多,详细可以参考http://api.jquery.com/jQuery.ajax)。

先来看看如何实现吧:

  1. <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>  
  2. <script type="text/javascript">  
  3.    $.ajax({  
  4.         url:"http://localhost:20002/MyService.ashx?callback=?",     
  5.         dataType:"jsonp",  
  6.         jsonpCallback:"person",  
  7.         success:function(data){  
  8.             alert(data.name + " is a a" + data.sex);  
  9.         }  
  10.    });  
  11. </script> 

没错,jsonpCallback就是可以指定我们自己的回调方法名person,远程服务接受callback参数的值就不再是自动生成的回调名,而是person。dataType是指定按照JSOPN方式访问远程服务。

利用jQuery可以很方便的实现JSONP来进行跨域访问。先暂时写到这吧。

分享到:
评论

相关推荐

    深入浅出Ajax(Head Rush Ajax) 源码 书中代码

    在"深入浅出Ajax"这本书中,作者深入讲解了Ajax的基本原理和实际应用。 **章节概览** 根据描述,这本书分为七章,每章可能涵盖以下关键知识点: 1. **第一章:初识Ajax** - Ajax的历史和概念 - Ajax工作原理的...

    深入浅出Ajax教程

    本教程《深入浅出Ajax》旨在全面讲解Ajax技术的各个方面,帮助读者掌握这一强大的工具。以下是一些关键知识点: 1. **XMLHttpRequest对象**:Ajax的核心就是XMLHttpRequest对象,它允许JavaScript在后台与服务器...

    深入浅出AJAX源码

    "深入浅出AJAX源码"这个主题旨在帮助开发者理解AJAX的工作原理,通过源码分析来提升对AJAX的实际应用能力。 首先,我们从第2章的代码开始。这一章可能涵盖了AJAX的基础知识,包括创建XMLHttpRequest对象,这是AJAX...

    深入浅出Ajax源码

    《深入浅出Ajax源码》是一本专注于解析Ajax技术核心原理的书籍,旨在帮助读者从源头上理解并掌握Ajax的工作机制。Ajax,全称为Asynchronous JavaScript and XML(异步JavaScript和XML),是一种在无需刷新整个网页的...

    AJAX深入浅出

    **AJAX 深入浅出** AJAX(Asynchronous JavaScript and XML)是一种在无需刷新整个网页的情况下,能够更新部分网页的技术。它通过在后台与服务器进行少量数据交换,使得网页实现异步更新,极大地提升了用户体验。...

    深入浅出ajax书中源码

    在"深入浅出Ajax"这本书中,作者深入剖析了Ajax的工作原理、核心技术和实际应用场景,旨在帮助读者掌握这一关键技术。 **1. Ajax工作原理** Ajax的核心是JavaScript的XMLHttpRequest对象,它允许浏览器在后台与...

    Head First深入浅出Ajax 中文版PDF

    《Head First深入浅出Ajax》是一本专门为初学者和进阶者设计的关于Ajax技术的中文版指南。这本书以其独特的视觉风格和易于理解的方式,详细介绍了Ajax的核心概念和技术,是JavaScript开发者深入理解Web异步通信的...

    深入浅出Ext JS(第2版) 随书光盘提供的书中实例

    《深入浅出Ext JS(第2版)》是一本详细解析Ext JS框架的权威书籍,其随书光盘包含了书中所有实例的源代码,这些代码对应于Ext JS的3.2.0版本。通过深入研究这些实例,读者可以更直观、更深入地理解Ext JS的强大功能和...

    ajax in action :ajax 实战 源码

    总之,《Ajax in Action》这本书深入浅出地介绍了Ajax技术,无论是对初学者还是有经验的开发者,都能从中受益。通过学习和实践书中的示例代码,读者将能够熟练掌握Ajax的使用,从而提升Web应用的性能和用户体验。

    《ajax入门经典》源代码

    10. **跨域问题与解决方案**:解释Ajax的同源策略限制,以及如何通过JSONP、CORS等方式解决跨域问题。 11. **Ajax安全考量**:分析Ajax应用可能遇到的安全风险,如XSS(跨站脚本攻击)、CSRF(跨站请求伪造)等,并...

    Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别

    前言  第一次听说jsonp,其实早在2年之前。当时在做一个活动页面的抽奖模块,要从服务端get一个概率,当时什么都不懂,同事说用ajax,我就用ajax,同事说...没关系,既然是深入浅出,那就从头说起。  假如我

    ajax佟刚老师源码

    7. **跨域问题**:探讨Ajax的同源策略限制及如何通过JSONP、CORS等方式解决跨域问题。 8. **jQuery/Ajax库**:对比原生JavaScript实现的Ajax与使用jQuery或其他库如axios、fetch的便利性。 9. **实战项目**:通过...

    ajax_in_action

    "Ajax in Action"这本书深入浅出地讲解了Ajax的核心概念和技术,对于想要深入了解和掌握Ajax技术的开发者来说是一本宝贵的资源。以下是基于书名和描述中的关键点,对Ajax及其相关技术的详细阐述: 1. **Ajax的基本...

    AJAX开发简略中文版

    在《AJAX开发简略中文版》这本书中,作者深入浅出地介绍了AJAX的基本概念、工作原理以及实际应用。书中不仅涵盖了AJAX的核心组成部分,如JavaScript、XMLHttpRequest对象、JSON和DOM操作,还提供了丰富的实例源代码...

    ajax深浅-入门到精通

    7. **跨域解决方案**:JSONP、CORS和WebSocket。 8. **前端路由和局部刷新**:在单页应用(SPA)中的Ajax实践。 通过深入学习和实践,你可以掌握Ajax的精髓,提升网页应用的交互性和性能,为用户提供更流畅的浏览...

    ajax 视频教程 2

    本“Ajax视频教程 2”深入浅出地讲解了Ajax技术,特别适合初学者和有一定基础的学习者。通过观看教程,你将能熟练掌握Ajax的使用,提升Web开发技能。 文件"ajax2.swf"可能是一个包含教程动画或互动示例的Flash文件...

    Ajax深入从入门到精通

    **Ajax 深入从入门到精通** ...书中结合实例,深入浅出地介绍了Ajax的各个方面,是掌握Ajax技术的好帮手。 通过阅读本书和实际操作,你将能够熟练运用Ajax构建高效、响应式的Web应用,为用户提供更优质的交互体验。

    疯狂ajax源代码第01-12章

    《疯狂Ajax》是李刚老师撰写的一本关于Ajax技术的权威著作,这本书深入浅出地讲解了Ajax在Web开发中的应用。源代码包含了第01到12章的内容,这让我们有机会通过实践来理解书中所讲述的概念和技术。下面将详细阐述...

    AJAX综合手册是综合技术的技术手册

    AJAX综合手册作为一本全面的技术指南,深入浅出地讲解了这一领域的各种概念、技术和最佳实践。 ### 1. AJAX基础 - **异步通信**:AJAX的关键特性是异步性,意味着用户在请求数据时可以继续与网页交互,而不会阻塞...

    Extjs深入浅出pdf

    深入浅出EXTJS 的PDF 文档无疑是一个宝贵的资源,适合那些希望深入了解该框架的开发者。以下是对文档中提到的一些关键知识点的详细解释: 1. **Ext.data**:EXTJS 的数据模块是其核心组件之一,它提供了一种在...

Global site tag (gtag.js) - Google Analytics