Js+MVC~公用API的设计,返回jsonp后使ajax的error属性生效!
相关知识说明
项目用公用的API事实上就是其它子项目,包括非子项目需要从这个项目中得到一个公用的信息,这种产生信息的接口我们称为公用的API(application program interface),例如:一个A网站,它有用户模块,产品模块,订单模块,帮助中心模组成,而在A网站旗下有它的A论坛,A社区,A微博等,而这些子网站的用户来源是从A网站来的,而如果在子网站中希望得到用户的详细信息,就需要我们在主网站提供一个开放的API,而这个API是如果通过GET请求直接访问的,这是正常的,但如果在A微博中需要异步得到信息,即以ajax方式得到信息,直接访问是不可以的,必须使用jsonp的方式!而对于jsonp来说,如果主网站的接口出现问题了,在默认情况下是不能通知到子网站的,这是jsonp自己的事,而jquery也提供了应对的方法,那就是jquery.jsonp插件,可以在这里下载!
说干就干
对于MVC开发环境来说,在视图渲染上提供了对html,javascript,text,json等渲染方式,如果jsonp来说,mvc本身并没有提供,事实上jsonp只是向页面输出json文本信息的变种,我们完全可以自己去伪造一个,当然把它封装的好一些就是要继承JsonResult,并在渲染方法ExecuteResult作一个文章就可以了,看代码:
1 /// <summary> 2 /// 返回jsonp上下文 3 /// </summary> 4 public class JsonpResult : JsonResult 5 { 6 const string CALLBACKNAME = "callback"; 7 /// <summary> 8 /// 复写渲染视图方法 9 /// </summary> 10 /// <param name="context"></param> 11 public override void ExecuteResult(ControllerContext context) 12 { 13 if (context == null) 14 { 15 throw new ArgumentNullException("当前请求上下文出错"); 16 } 17 if ((JsonRequestBehavior == JsonRequestBehavior.DenyGet) 18 && String.Equals(context.HttpContext.Request.HttpMethod, "GET")) 19 { 20 throw new InvalidOperationException("Jsonp只能是GET请求"); 21 } 22 var response = context.HttpContext.Response; 23 if (!String.IsNullOrEmpty(ContentType)) 24 { 25 response.ContentType = ContentType; 26 } 27 else 28 { 29 response.ContentType = "application/json"; 30 } 31 if (ContentEncoding != null) 32 { 33 response.ContentEncoding = this.ContentEncoding; 34 } 35 if (Data != null) 36 { 37 String buffer; 38 var request = context.HttpContext.Request; 39 var serializer = new JavaScriptSerializer(); 40 if (request[CALLBACKNAME] != null) 41 buffer = String.Format("{0}({1})", request[CALLBACKNAME], serializer.Serialize(Data)); 42 else 43 buffer = serializer.Serialize(Data); 44 response.Write(buffer); 45 } 46 } 47 }
而对于公用的API来说,我们可以在controller里这样去写:
1 /// <summary> 2 /// 跨域API 3 /// </summary> 4 /// <returns></returns> 5 public JsonpResult GetUserAPI(string userID) 6 { 7 JsonpResult result = new JsonpResult() 8 { 9 Data = new { name = "zzl", res = true, }, 10 JsonRequestBehavior = JsonRequestBehavior.AllowGet 11 }; 12 return result;//反回一个callback(msg)对象 13 }
OK,底层获到公用信息的工作已经完成了,再看一下如何在A微博页面上去调用它:
1 //跨域调用公用的API,如果希望它相应error事件,需要使用$.jsonp,而不是JQ的$.ajax 2 function jsonpFun() { 3 $.ajax({ 4 dataType: 'jsonp', //跨域使用它 5 jsonp: 'callback', //可以省略,但如果显示声明它,必须是callback,因为在JsonResult里jsonp字符串已经被规定成它了 6 url: 'http://www.jsonp.com/Common/GetUserAPI', 7 data: { userID: 1 }, 8 type: 'GET', 9 success: function (data) { 10 alert(data.name); 11 }, 12 error: function (data) { 13 alert("获取用户信息失败"); 14 } 15 }); 16 }
上面的代码应该改为:
1 $.jsonp({ 2 url: 'http://www.jsonp.com/Common/GetUserAPI?userID=1', 3 callbackParameter: 'callback', 4 success: function (data) { 5 alert(data.name); 6 }, 7 error: function (xOptions, textStatus) { 8 alert("获取用户信息失败"); 9 } 10 });
好了,前面已经说了对于jsonp来说,ajax的error属性是不好使的,我们需要在页面上引用jquery.jonsp这个js插件才行:
1 <script src="http://www.cnblogs.com/Scripts/jquery.jsonp-2.3.0.min.js" type="text/javascript"></script>
OK,我们测试一下吧:
没有问题,信息已经得到了,再看看fiddler所捕获的消息:
我们的URL上自己加上了callback,而这个串是A网站与A微博网站自己规定的,如果您不知道它们的规范,这个请求是会失败的,这是正常的,呵呵。
通过GET请求,直接可以返回你要的字符,这也是正常的,当然实现项目中,我们会在双方进行密文的设计的!