[JSONP]使用jQuery + JSONP + ASP.NET跨網域取得伺服器端資料的方式

最近小喵遇到一個需要跨網域從client端取遠端伺服器中值的問題,最開始直接的想法,透過jQuery的Ajax應改可以輕鬆的收工。不過因為跨了網域,瀏覽器安全性考量的情況下,是不允許直接透過ajax的方式取值。於是開始在網路上找尋相關的解決方案。終於看到一個名為JSONP的方式。

緣起

最近小喵遇到一個需要跨網域從client端取遠端伺服器中值的問題,最開始直接的想法,透過jQuery的Ajax應改可以輕鬆的收工。不過因為跨了網域,瀏覽器安全性考量的情況下,是不允許直接透過ajax的方式取值。於是開始在網路上找尋相關的解決方案。終於看到一個名為JSONP的方式。

 

JSON

JSON是在Javascript中資料物件的一種格式,如果您還不太清楚JSON的格式與意義,或許您可以參考Wiki對於JSON的解說先。

在了解JSON之後,如果沒有跨網域的情況下,可以透過jQuery的$.getJSON輕鬆地從後端取得JSON格式的資料,而在Server端的程式,如果使用ASP.NET的話,也可以透過JSON.NET輕鬆地將.NET裡面的物件,轉成JSON的格式[參考黑暗執行緒的這篇]。

 

JSONP的原理

有了以上的準備後,我們知道在Javascript裡面要去從ASP.NET裡面要去取得JSON是很簡單的事,但是一旦跨了網域,就沒有這麼美好了,原因是為了安全起見,瀏覽器不允許跨網域Ajax遠端存取。

生命會自己找出生路的。的確,在這樣的限制中,於是有人開始去尋找有什麼方式可以跨網域。發現了Javascript可以跨網域取得的,就是從遠端抓取【.js】的Javascript Library,例如以下的語法:

<script src="http://www.abc.com.tw/js/test.js"></script>

而JSONP就是由這樣的方式衍生出來的。

接著來看一下以下的HTML與JS,來了解JSONP最最原始的概念

首先是一個在機器A上面的HTML,內容如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript">
        //這個function讓遠端的.js呼叫並將資料透過data傳遞
        function CallBackFunction(data) {
            alert(data);
        }
    </script>
</head>
<body>

</body>
</html>

接著,在機器B上的IIS中,準備一個.js的Javascript檔案,裡面的內容如下:

//呼叫引用端預定已經寫好的function:CallBackFunction
CallBackFunction("從遠端傳回來的資料");

這個js內容非常單純,就是呼叫一個名為CallBackFunction的Javascript function,但是這個function並沒有在這支.js裡面,而是寫在引用此js的檔案中(上面的HTM)

接著,HTM中,在<body></body>中,加上一段引用機器B上面的js,完整語法如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript">
        //這個function讓遠端的.js呼叫並將資料透過data傳遞
        function CallBackFunction(data) {
            alert(data);
        }
    </script>
</head>
<body>
    <!--引用遠端的js檔-->
    <script type="text/javascript" src="http://ServerB/PJ1/js/test.js"></script>
</body>
</html>

執行結果,就會跳出一個alert,顯示【從遠端傳回來的資料】

以上的範例是一個非常簡單的範例,但是卻顯現出JSONP的最基本精神,透過引用遠端的JS,把要傳遞的資料夾帶在裡面,然後從中呼叫本端的function來處理傳遞過去的資料。這就是JSONP的最基本精神,只要把剛剛顯示出來的資料,換成JSON的資料,就是JSONP的基本原理了。

 

getJSON + 遠端的JSON資料

有了以上對於JSONP的認識後,接著就來看看要怎麼來透過jQuery的getJSON,從遠端的ASP.NET裡面去取得JSON資料。

需透過【GET】的方式傳遞資料

由於是透過網址去引用遠方的Javascript,因此想當然爾,如果有資料要送給遠端,不可能透過POST的方式做Submit Form,必須透過GET的方式,把要傳遞給遠端Server的資料(例如Key值)帶在QueryString裡面。而希望到時候要呼叫本端的哪個function名稱,也是透過一個QueryString來傳遞,通常會用【callback】這樣的QueryString變數名稱。

事先要說明的大致說明了,接著就直接來看範例:

首先,在A機器上,我們有一支html或者aspx,裡面的內容如下:

我們在畫面上安排一個txt1, btn1,還有一個span1。希望btn1按下後,跨網域引用遠端的aspx,由該aspx丟出javascript的語法來執行。

以下是A機器上的相關程式碼:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="js/jquery.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#btn1').click(btn1_click);
        });
        var sRlt = '';

        //btn1按下後處理的動作,把Txt1的內容透過QueryString變數UId來傳遞
        function btn1_click() {
            var strURL = 'http://ServerB/PJ1/T2_S.aspx?UId=' + $('#txt1').val();
            alert(strURL);
            
            //透過getJSON呼叫遠端的aspx,IE的話記得要用以下的方式才能正常運作
            $.getJSON(strURL + '&callback=?', jsonp_callback);
        }

        //callback回來呼叫的function,處理資料並且放在span1裡面
        function jsonp_callback(data) {
            alert(data);
            sRlt += 'UName:' + data.UName + '<br>';
            sRlt += 'Tel:' + data.Tel + '<br>';
            sRlt += 'UId:' + data.UId;
            $('#span1').html(sRlt);
        }

    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <input id="txt1" type="text" />
        <input id="btn1" type="button" value="取得" />
        <hr />
        <span id="span1">I'm span1.</span>
    </div>
    </form>
</body>
</html>

而Server端的aspx,首先是畫面中的html相關Tag都不要,只保留如下的內容

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="T2_S.aspx.vb" Inherits="T2_S" %>

 

接著在CodeFile中,小喵寫了一個小物件,用來代表從資料庫中查詢到的資料,放入物件中

Public Class Usr
    Private m_UName As String
    Private m_Tel As String
    Private m_UId As String

    Public Property UName As String
        Get
            Return m_UName
        End Get
        Set(value As String)
            m_UName = value
        End Set
    End Property

    Public Property Tel As String
        Get
            Return m_Tel
        End Get
        Set(value As String)
            m_Tel = value
        End Set
    End Property

    Public Property UId As String
        Get
            Return m_UId
        End Get
        Set(value As String)
            m_UId = value
        End Set
    End Property

End Class

並且透過JSON.NET,將.NET的物件轉為JSON的格式

判斷是否有傳入callback的QueryString,如果有,多產生呼叫callback function的部分,相關程式如下:

Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    '建立新物件
    Dim u As New Usr
    '這裡假設從從資料庫抓到的資料,然後給予物件相關的屬性內容
    u.UId = Request.QueryString("UId")
    u.UName = "topcat" & u.UId
    u.Tel = u.UId & "_2044"

    '透過JSON.NET將物件轉為JSON格式
    Dim j As String = JsonConvert.SerializeObject(u)

    '判斷是否有傳入callback的function名稱
    If Request.QueryString("callback") <> "" Then
        Dim CallBackFunction As String = Request.QueryString("callback")
        '傳回的內容加上呼叫callback的function
        j = CallBackFunction & "(" & j & ");"
    End If
    '輸出JSONP的內容
    Response.Write(j)

End Sub

 

這樣就可以透過JSONP的機制,跨網域的去抓取遠端主機的相關資料,傳回JSON格式了。

 


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~Now)