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=' + rNumber10 : 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 else13 {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类库中了,地址如下: