JSON跨域原理实现

  Ajax不能跨域访问有时候的确有点头疼,但是又不得不这样,如果真的可以跨域了,那就太可怕了。在做PhoneGap开发的时候,将HTML/JavaScript/CSS/Image等文件打包在APK中的时候,如果需要与服务器端数据交互就会产生这个问题,那么有几种方式解决这个数据交互的问题:

  1、WebSocket:很强大,不过服务器端要写代码,还要分配socket端口;主要是有些平台内置浏览器不支持WebSocket,且需要写PhoneGap扩展。

  2、内嵌Frame:可以在网页中内嵌一个frame,载入服务器端脚本,这样保证在同一个域下请求数据;这种可用性差,需要保证子框架与父框架的数据沟通。

  3、JSONP:在JQuery里有Ajax方法中可以设定dataType为JSONP后实现跨域访问。

  在web开发中,前端的JavaScript类库,是可以跨域调用的;在上一篇的博客中写过动态载入JavaScript类库:

 1         LoadScript : function (url, callback) {
 2             var superarg = arguments;
 3             var script = document.createElement("script")
 4             script.type = "text/javascript";
 5             document.getElementsByTagName("head")[0].appendChild(script);
 6             script.onload = function () {
 7                 if (callback) callback();
 8             };
 9             script.onerror = function(e){
10                 console.log('LoadScript error, url : ' + url);
11                 superarg.callee(url, callback);
12             };
13             script.src = url;
14         },

  根据这个原理,服务器端返回的不是JSON数据,而且一个JavaScript脚本,这个脚本中包含了JSON数据,那么在发送之前随机生成一个方法名发送到服务端,服务端返回用这个方法执行所需要的JSON数据,那么在JS被载入到页面中后,便开始执行这个方法,一旦执行这个方法,就可以callback需要执行的函数了,这样就实现了JSON数据跨域请求了,代码如下:

 1         getJSON : function (url, callback, complete){
 2             var rNumber = '_';
 3             var reg = /[\?\&]callback=([_\-a-zA-Z0-9]*)/;
 4             if(!reg.test(url)) {
 5                 for (var i = 0; i < 10; i++) {
 6                     rNumber += Math.floor(Math.random() * 10);
 7                 };
 8                 url.indexOf('?') != -1
 9                     ? url += '&callback=' + rNumber
10                     : url += '?callback=' + rNumber;
11             }
12             else{
13                 var m = reg.exec(url);
14                 if(m && m.length > 1){
15                     rNumber = m[1];
16                 }
17             }
18 
19             global[rNumber] = function (data) { 
20                 if (this.fn) this.fn(eval(data));
21                 delete global[this.fnName];
22             }
23             .bind( { fn : callback, fnName : rNumber } );
24 
25             var script = document.createElement("script")
26             script.type = "text/javascript";
27             document.getElementsByTagName("head")[0].appendChild(script);
28             script.onload = function () {
29                 complete && complete();
30                 $(script).remove();
31             };
32             script.onerror = function(e){
33                 console.log('LoadScript error, url : ' + url);
34             };
35             script.src = url;
36         }

  服务器端是asp.net MVC,代码如下:

 1     public class JsonpResult : System.Web.Mvc.JsonResult
 2     {
 3         public override void ExecuteResult(ControllerContext context)
 4         {
 5             if (context != null)
 6             {
 7                 HttpResponseBase response = context.HttpContext.Response;
 8                 if (!string.IsNullOrEmpty(ContentType))
 9                 {
10                     response.ContentType = ContentType;
11                 }
12                 else
13                 {
14                     response.ContentType = "application/javascript";
15                 }
16                 if (ContentEncoding != null)
17                 {
18                     response.ContentEncoding = ContentEncoding;
19                 }
20                 if (Data != null)
21                 {
22                     HttpRequestBase request = context.HttpContext.Request;
23                     JavaScriptSerializer serializer = new JavaScriptSerializer();
24                     response.Write(request.Params["callback"] + "(" + serializer.Serialize(Data) + ")");
25                 }
26             }
27         }
28     }

已将这段代码放入以前实现的JQuery类库中了,地址如下:

https://github.com/Visolleon/H5Query

posted @ 2012-08-28 14:32  Visolleon  阅读(453)  评论(0编辑  收藏  举报