最近小喵遇到一個需要跨網域從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格式了。
以下是簽名:
- 歡迎轉貼本站的文章,不過請在貼文主旨上加上【轉貼】,並在文章中附上本篇的超連結與站名【topcat姍舞之間的極度凝聚】,感恩大家的配合。
- 小喵大部分的文章會以小喵熟悉的語言VB.NET撰寫,如果您需要C#的Code,也許您可以試著用線上的工具進行轉換,這裡提供幾個參考
Microsoft MVP Visual Studio and Development Technologies (2005~2019/6) | topcat Blog:http://www.dotblogs.com.tw/topcat |