ASP.NET 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獲取到了數據,和上面的一樣


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM