• MVC 定义JsonpResult实现跨域请求


    MVC 定义JsonpResult实现跨域请求

    1:原理

    在js中,XMLHttpRequest是不能请求不同域的数据,但是script标签却可以,所以可以用script标签实现跨域请求。具体是定义一个函数,例如jsonp1234,请求不同域的url时带上函数名,例如:http://otherdomain.com/index?callback=jsonp1234,然后服务端根据callback获取这个函数名,然后传入json字符串作为函数参数。

    2:实现

    http://localhost:62203/home/index页面代码如下

    复制代码
    @{
        Layout = null;
    }
    
    <!DOCTYPE html>
    
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Index</title>
        <script>
        function showMessage(result) {
            alert(result.name)
        }
        </script>
        <script src="http://localhost:16308/home/index?callback=showMessage" type="text/javascript"></script>
    </head>
    <body>
        <div> 
        </div>
    </body>
    </html>
    复制代码

    主要是这句  

    <script src="http://localhost:16308/home/index?callback=showMessage" type="text/javascript"></script>,

    可以看到,访问的是不同的站点,并且callback的参数值为showMessage,

    http://localhost:16308/home/index代码如下

    复制代码
    public ActionResult Index()
            {
                string callback = this.Request["callback"];
                string json="{"name":"server"}";
                this.Response.Write(callback + "(" + json + ")");
                return new EmptyResult();
            }
    复制代码

    根据callback获取函数名,然后将json字符串作为函数参数。

    访问页面http://localhost:62203/home/index,效果如下

    image

    可见,站点localhost:62203从站点localhost:16308获取到了数据。 

    但是我们看服务端的实现,这也太不美观,也比较麻烦。

    复制代码
    public ActionResult Index()
            {
                string callback = this.Request["callback"];
                string json="{"name":"server"}";
                this.Response.Write(callback + "(" + json + ")");
                return new EmptyResult();
            }
    复制代码

    我们想要的是调用一个方法,就能实现跨域了,那如何实现呢。看到Controller有个this.Json方法,类型是JsonResult,我们可以参考这个类。定义一个类JsonpResult,派生于JsonResult,在ExecuteResult方法根据callback获取函数名,然后传入json字符串作为函数参数。

    复制代码
    public class JsonpResult : JsonResult
        {
            public static readonly string JsonpCallbackName = "callback";
            public static readonly string CallbackApplicationType = "application/json";
    
            public override void ExecuteResult(ControllerContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }
                if ((JsonRequestBehavior == JsonRequestBehavior.DenyGet) &&
                      String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
                {
                    throw new InvalidOperationException();
                }
                var response = context.HttpContext.Response;
                if (!String.IsNullOrEmpty(ContentType))
                    response.ContentType = ContentType;
                else
                    response.ContentType = CallbackApplicationType;
                if (ContentEncoding != null)
                    response.ContentEncoding = this.ContentEncoding;
                if (Data != null)
                {
                    String buffer;
                    var request = context.HttpContext.Request;
                    var serializer = new JavaScriptSerializer();
                    if (request[JsonpCallbackName] != null)
                        buffer = String.Format("{0}({1})", request[JsonpCallbackName], serializer.Serialize(Data));//首先根据callback获取获取函数名,然后传入json字符串作为函数参数
                    else
                        buffer = serializer.Serialize(Data);
                    response.Write(buffer);
                }
            }
        }
    复制代码

    JsonpResult类有了,但是想在Controller这样使用this.Jsonp,所以为Controller类定义一个扩展方法,

    复制代码
    public static class ControllerExtension
        {
            public static JsonpResult Jsonp(this Controller controller, object data)
            {
                JsonpResult result = new JsonpResult()
                {
                    Data = data,
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                }; 
                return result;
            }
        }
    复制代码


    这是在Controller就可以直接使用this.Jsonp了,把跨域服务端的代码改下

    public ActionResult Index()
            {
                return this.Jsonp(new { name = "server JsonpResult" });
            }

    相比上面那个简洁多了

    再次打开http://localhost:62203/home/index

    image

    同样,站点localhost:62203从站点localhost:16308获取到了数据,和上面的一样

  • 相关阅读:
    宏任务、微任务
    类和模块
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4759034.html
Copyright © 2020-2023  润新知