• Jsonp简单认识(后端使用的是asp.net mvc)


    一、Jsonp简介:由于浏览器基于安全有同源策略(同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性)机制,所以前端无法使用Ajax来获取来获取其他域名下返回的数据,而Jsonp可以实现跨域访问。

      Jsonp是基于<script>标签不受同源策略限制,可以加载任意地方的JavaScript文件来实现的。Jsonp实现理念就是,和服务端约定好一个函数名,当请求文件时,服务端返回一段JavaScript。这段JavaScript调用了约定好的函数,并且将数据当做参数传入。

    二、简单Demo

    1、在visual studio新建项目JsonpDemo和项目OtherDomain,项目结构如下

    2、在JsonpDemo项目中新增HomeController及其视图,视图中代码如下:

     1 @{
     2     Layout = null;
     3 }
     4 
     5 <!DOCTYPE html>
     6 
     7 <html>
     8 <head>
     9     <meta name="viewport" content="width=device-width" />
    10     <title>Index</title>
    11 </head>
    12 <body>
    13     <div>
    14         <input type="button" id="getJsonpByHand" value="get jsonp by hand" />
    15     </div>
    16     <script type="text/javascript" >
    17         $("#getJsonpByHand").click(function () {
    18        //55157位OtherDomain项目启动后网站的端口
    19             CreateScript("http://localhost:55157/home/somejsonp?");
    20         })
    21         function CreateScript(src) {
    22             $("<script><//script>").attr("src", src).appendTo("body")
    23         }
    24      //myCallBack就是与后端约定好的函数
    25         function myCallBack(data) {
    26             console.log(data);
    27         }
    28     </script>
    29 </body>
    30 </html>
    View Code

    3、在OtherDomain项目中新增HomeController及其视图,HomeController中代码如下:

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace OtherDomain.Controllers
    {
        public class HomeController : Controller
        {
            //
            // GET: /Home/
    
            public ActionResult Index()
            {
                return View();
            }
    
            public ActionResult SomeJsonp()
            {
                return new ContentResult()
                {
                    //myCallBack为服务端与前端约定好的函数
                    Content = "myCallBack(" + JsonConvert.SerializeObject(new { Name = "Tom", Age = 23 }) + ")",
                    ContentType = "text/html"
                };
            }
    
        }
    }
    View Code

    4、启动两个项目,点击JsonpDemo项目页面中的按钮,谷歌浏览器控制台下看到

    三、对上面Demo做一下简单优化,可以通过前端来指定与服务器约定的函数

    1、修改JsonpDemo项目index.cshtml页面中,按钮点击事件下CreateScript方法传入参数为:http://localhost:55157/home/somejsonp?callback=myCallBack 也就是加上一个URL参数

    2、修改OtherDomain项目下HomeController.cs中SomeJsonp方法如下:

            public ActionResult SomeJsonp()
            {
                string func = Request.Params["callback"];
                return new ContentResult()
                {
                    Content = func+"(" + JsonConvert.SerializeObject(new { Name = "Tom", Age = 23 }) + ")",
                    ContentType = "text/html"
                };
            }

    四、通过jQuery使用Jsonp实现跨域请求

    1、继续沿用上面两个项目,修改JsonpDemo项目index.cshtml页面代码,新增一个按钮,并实现其click事件相关代码,如下:

    @{
        Layout = null;
    }
    
    <!DOCTYPE html>
    
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Index</title>
        <script src="~/Scripts/jquery-1.8.2.min.js"></script>
    </head>
    <body>
        <div>
            <input type="button" id="getJsonpByHand" value="get jsonp by hand" />
             <input type="button" id="getJsonpByJquery" value="get jsonp by jquery" />
        </div>
        <script type="text/javascript" >
            $("#getJsonpByHand").click(function () {
                CreateScript("http://localhost:55157/home/somejsonp?callback=myCallBack");
            })
            function CreateScript(src) {
                $("<script><//script>").attr("src", src).appendTo("body")
            }
            $("#getJsonpByJquery").click(function () {
                $.ajax({
                    // url: 'http://localhost:55157/home/somejsonp?callback=myCallBack',
                    url: 'http://localhost:55157/home/somejsonp',
                    dataType: "jsonp",
                    jsonp: "callback",
                    success: function (data) {
                        console.log(data)
                        var a=123;
                        var b=2;
                        var c=35;
                    }
                })
            })
            //function myCallBack(data) {
            //    console.log(data);
            //}
        </script>
    </body>
    </html>
    View Code

    注意上面ajax参数dataType为jsonp,jsonp为callback

    2、OtherDomain下HomeController.cs文件SomeJsonp代码和第三个里面代码一样,如下:

      public ActionResult SomeJsonp()
            {
                string func = Request.Params["callback"];
                return new ContentResult()
                {
                    Content = func + "(" + JsonConvert.SerializeObject(new { Name = "Tom", Age = 23 }) + ")",
                    ContentType = "text/html"
                };
            }
    View Code

    3、运行两个项目,点击“get jsonp by jquery”按钮,可以在谷歌浏览器控制台下看到同样结果

    4、注意:如果前端代码传入callback参数,那么前端也要自己实现相应参数的函数。如果没有传入,其实jQuery自己会默认传入并自己实现。

    五、扩展:在OtherDomain项目下,简单自定义JsonpResult类,代码如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Mvc;
     6 
     7 namespace OtherDomain
     8 {
     9     public class JsonpResult : JsonResult
    10     {
    11         private const string CALLBACK_QUERYSTRING = "callback";
    12         //private const string CALLBACK_CONTENTTYPE = "application/x-javascript";
    13         private const string CALLBACK_CONTENTTYPE = "text/javascript";
    14 
    15         public override void ExecuteResult(ControllerContext controllerContext)
    16         {
    17             if (controllerContext != null)
    18             {
    19                 var request = controllerContext.HttpContext.Request;
    20                 object callback = request[CALLBACK_QUERYSTRING];
    21                 if (callback == null)
    22                 {
    23                     controllerContext.RouteData.Values.TryGetValue(CALLBACK_QUERYSTRING, out callback);
    24                 }
    25 
    26                 var hasCallback = !string.IsNullOrWhiteSpace(callback == null ? "" : callback as string);
    27                 if (hasCallback)
    28                 {
    29                     SetContentTypeIfEmpty();
    30                     var response = controllerContext.HttpContext.Response;
    31                     response.Write(callback);
    32                     response.Write("(");
    33                     base.ExecuteResult(controllerContext);
    34                     response.Write(")");
    35                 }
    36                 else
    37                 {
    38                     base.ExecuteResult(controllerContext);
    39                 }
    40             }
    41         }
    42 
    43         private void SetContentTypeIfEmpty()
    44         {
    45             if (string.IsNullOrWhiteSpace(base.ContentType))
    46             {
    47                 base.ContentType = CALLBACK_CONTENTTYPE;
    48             }
    49         }
    50     }
    51 
    52     public static class ContollerExtensions
    53     {
    54         public static JsonpResult Jsonp(this Controller controller, object data, JsonRequestBehavior behavior = JsonRequestBehavior.DenyGet)
    55         {
    56             JsonpResult result = new JsonpResult();
    57             result.Data = data;
    58             result.JsonRequestBehavior = behavior;
    59             return result;
    60         }
    61     }
    62 }
    JsonpResult及ContollerExtensions

    如果想要很好的结合到controller中,需要写如上ContollerExtensions的Controller的扩展方法

    在OtherDomain项目下,需要修改SomeJsonp方法:

          public ActionResult SomeJsonp()
            {
                return this.Jsonp(new
                {
                    Name= "Tom",
                    Age=23
                }, JsonRequestBehavior.AllowGet);
            }
  • 相关阅读:
    ffmpeg推流
    linux nfs挂载根文件系统失败
    ffmpeg nginx rtmp推流
    sql 随机生成NewId
    C#/.NET 异步操作会生成新线程吗
    SQLServer的数据库邮件和SQLServer代理(作业)
    C# ThreadPool类(线程池)
    SQL Server查看执行计划
    从0开始基于Webpack5 搭建HTML+Less 前端工程
    Vue 父子级的相互调用
  • 原文地址:https://www.cnblogs.com/hujiapeng/p/4914335.html
Copyright © 2020-2023  润新知