相关知识说明
项目用公用的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= type="text/javascript"></script>
OK,我们测试一下吧:
没有问题,信息已经得到了,再看看fiddler所捕获的消息:
我们的URL上自己加上了callback,而这个串是A网站与A微博网站自己规定的,如果您不知道它们的规范,这个请求是会失败的,这是正常的,呵呵。
通过GET请求,直接可以返回你要的字符,这也是正常的,当然实现项目中,我们会在双方进行密文的设计的!
作者:仓储大叔,张占岭,
荣誉:微软MVP