关于 JSONP,我想大家都已经很熟悉了,还不是很清楚的童鞋可以在网上搜索一下。众所周知, Ajax 是不能跨域请求的,默认情况下,浏览器是阻止的。那如何来实现跨域提供服务呢?举一个很简单的例子。比如我现在有一个网站 www.abc.com ,其中有一个页面需要提供百度的搜索框,并且还要像百度首页一样,提供智能的提示,就是在我输入文字的同时,及时补全我的搜索,列出供我选择的项。
由于前面我们说到 Ajax 是不能跨域的,那怎样调用百度的搜索服务呢?答案就是 JSONP。JSONP 说白了就是在 www.abc.com 一个页面里,通过 Javascript 动态构造一个 <Script> </script>,其中 src= 'http://search.baidu.com/service.php?word=博客园&callback=showSearch", 其中 word=博客园 是我们在 www.abc.com 搜索框里面输入的文字,callback=showSearch 就是百度返回的结果里面回调函数的名称,比如 showSearch({ word: '博客园', result : [{博客园a},{博客园b}] }) 。
由于动态构建 <script> 不是 Ajax 请求,而是普通的 GET 请求,所以它是可以跨域的。
废话了这么多,下面就贴出我的代码了:
JsonpResult:
using System.Web.Mvc; using System.Web.Script.Serialization; using System.Text; namespace DearBruce.JsonpActionResultDemo.WebUI.Extensions { /// <summary> /// Jsonp 返回结果 /// </summary> public class JsonpResult : ActionResult { /// <summary> /// 默认的 callback 参数名称 /// </summary> public static readonly string _defaultCallbackName = "jsoncallback"; /// <summary> /// 默认的密码的参数名称 /// </summary> public static readonly string _defaultPasswordName = "password"; /// <summary> /// 构造函数 /// </summary> /// <param name="data">要序列化为 Jsonp 数据的对象</param> public JsonpResult(object data) : this(data, null) { } /// <summary> /// 构造函数 /// </summary> /// <param name="data">要序列化为 Jsonp 数据的对象</param> /// <param name="callbackName">回调函数的名字,如果为空,则默认为 "jsoncallback"</param> public JsonpResult(object data, string callbackName) { this.Data = data; this.CallBackName = callbackName; } /// <summary> /// 验证权限 /// </summary> /// <param name="context">控制器上下文</param> /// <returns>授权是否成功,如果已经授权,则返回 true</returns> protected virtual bool ValidatePrivilege(ControllerContext context) { if (!string.IsNullOrEmpty(PasswordValue)) { // 这里验证密码是否正确 string password = context.HttpContext.Request.QueryString[PasswordName]; if (password != PasswordValue) { return false; } } return true; } /// <summary> /// 核心处理 /// </summary> /// <param name="context"></param> public override void ExecuteResult(ControllerContext context) { if (!ValidatePrivilege(context)) { HandleUnAuthorizedRequest(context); return; } string jsonData = null; if(Data != null) { jsonData = new JavaScriptSerializer().Serialize(Data); } string callbackValue = context.HttpContext.Request.QueryString[CallBackName]; string result; string contentType; if (string.IsNullOrEmpty(callbackValue)) { result = jsonData; contentType = "application/json"; } else { result = callbackValue + "(" + jsonData + ")"; contentType = "application/x-javascript"; } context.HttpContext.Response.ContentType = contentType; if (this.ContentEncoding != null) { context.HttpContext.Response.ContentEncoding = this.ContentEncoding; } if(result != null) { context.HttpContext.Response.Write(result); } } /// <summary> /// 处理为授权的请求 /// </summary> /// <param name="context">控制器上下文</param> protected virtual void HandleUnAuthorizedRequest(ControllerContext context) { // 暂时不实现 //context.HttpContext.Response.ContentType = "text/plain"; //context.HttpContext.Response.Write(string.Empty); } /// <summary> /// 要序列化为 Jsonp 数据的对象 /// </summary> public object Data { get; set; } private Encoding _contentEncoding; /// <summary> /// 内容编码 /// </summary> public Encoding ContentEncoding { get { return _contentEncoding; // ?? Encoding.UTF8; } set { _contentEncoding = value; } } private string _callBackName; /// <summary> /// 回调函数名称 /// </summary> public string CallBackName { get { return _callBackName ?? _defaultCallbackName; } set { _callBackName = value; } } private string _passwordName { get; set; } /// <summary> /// 密码的参数名称,默认为 "password" /// </summary> public string PasswordName { get { return _passwordName ?? _defaultPasswordName; } set { _passwordName = value; } } /// <summary> /// 正确的密码值 /// </summary> public string PasswordValue { get; set; } } }
测试的 Controller:
public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "欢迎使用 ASP.NET MVC!"; return View(); } public ActionResult TestJsonp1() { return new JsonpResult(new { success = true, message = "测试 jsonp1" }); } public ActionResult TestJsonp2() { return new JsonpResult(new { success = true, message = "测试 jsonp2" }, "callback"); } public ActionResult TestJsonp3() { JsonpResult result = new JsonpResult(new { success = true, message = "测试 jsonp3" }, "callback") { PasswordValue = "bruce123456", }; return result; } }
测试的 View:
<p> @Html.ActionLink("测试 Jsonp 之不带 jsoncallback 参数和不需要密码,则返回 json 数据", "TestJsonp1") </p> <p> @Html.ActionLink("测试 Jsonp 之带 callback 参数,则返回 javascript 代码", "TestJsonp2", new { callback = "ShowMessage" }) </p> <p> @Html.ActionLink("测试 Jsonp 之需要密码 - 为空或错误的密码", "TestJsonp3") </p> <p> @Html.ActionLink("测试 Jsonp 之带 callback 参数和需要密码 - 正确的密码", "TestJsonp3", new { password = "bruce123456", callback = "ShowMessage" }) </p>
虽然很简单,只给需要帮助的人!
谢谢浏览!