RESTful探索2-使用jQuery AJAX呼叫RESTful Web Service
0 |
前篇文章提到RESTful Web Service的幾點特性:
- 使用URI來代表目標資源,在CRUD情境中目標資源就是要查詢或更新的資料。
- 使用不同的HTTP Method來區別操作,使用GET、POST、PUT、DELETE分別代表查詢、新增、修改、刪除動作。
- 除了HTTP Method,HTTP Status Code也用來表示執行結果,例如傳回HTTP 404表示查詢不到;當新增資料完成傳回HTTP 201並在Response Header使用Location指向查詢該筆資料的URI。
第1點是單純的Server端Routing要求,而2,3點需要Server及Client雙方都支援。在ASP.NET中,Request.HttpMethod可用來判別Client端指定的方法,指定Response.StatusCode則可指定201, 404, 500等不同狀態碼,而201時需要在Response Header加料的需求,可透過Response.AppendHeader()達成,這些對ASP.NET來說都是一塊蛋糕,毋需擔心。回到Client端,過去在寫jQuery,常使用的$.get(), $.post()並無法滿足自訂HTTP Method及處理特定Status Code的需求,但不用擔心,回歸到彈性十足的$.ajax(),就能輕鬆搞定。
要呼叫RESTful Web Service,我們會用到jQuery.ajax()的幾項設定參數:
- url
指向資源的URL位址 - type
可傳入"GET", "POST", "PUT", "DELETE",指定發出Request的HTTP Method - contentType
指定Request內容的MIME型別,在POST/PUT/DELETE時,多半需傳送待新增刪資料物件的JSON字串,故多會設成"application/json; charset=UTF-8"供Server端識別。 - data
在POST/PUT/DELETE時多會使用data: JSON.stringify(dataObject)的方式,將Client端資料物件轉為JSON字串後抛至Server端。 - statusCode
可指定當前端傳回特定狀態碼時要執行的動作,例如:
statusCode: {
201: function(data, statusText, xhr) { … }
404: function(xhr, statusText, err) { … },
500: function(xhr, statusText, err) { … }
}
代表當回傳結果是201, 404及500時,分別執行三段不同邏輯。要注意的是,在加掛statusCode事件時,若網頁回傳結果正常(指Status Code=2xx或304),sucess: function(data, statusText, xhr)一樣會被觸發;若狀態碼不等於2xx與304,則error: function(xhr, statusTExt, err)也會被觸發。所以statusCode裡宣告的事件會被額外執行,而非取代原有的success及error,且傳入的參數也會依狀態碼而有所不同,當狀態碼為2xx或304時,比照success,會傳入data, statusText及xhr;反之則比照error,可取得xhr, statusText及err。
前述的xhr物件,另外提供了responseText/responseXML及getResponseHeader()... 等,可用來取得傳回結果的原始資料及Response Header。
以下是我整理好的$.ajax() REST應用範例。分別測試HttpMethod == "DELETE"、回傳StatusCode=404、StatusCode=201並傳回Location Header、直接丟出Exception、使用StatusCode=500表示出錯並傳回錯誤資訊。這裡先不導入ASP.NET Routing,直接用WebForm.aspx?test=…的方式執行各種測試,我另外還多提供直接用Iframe導向WebForm.aspx?test=...顯示網頁,做為與$.ajax()存取做法的對照。
<%@ Page Language="C#" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
string testItem = Request["test"];
if (!string.IsNullOrEmpty(testItem))
{
//測試1, 顯示HTTP Method
if (testItem == "method")
Response.Write("HttpMethod=" + Request.HttpMethod);
//測試2, 傳回HTTP 404
else if (testItem == "404")
Response.StatusCode = 404;
//測試3, 傳回HTTP 201及Location header
else if (testItem == "201")
{
Response.StatusCode = 201;
Response.AppendHeader("Location",
"http://blog.darkthread.net");
}
//測試3, 故意引發錯誤,傳回ASP.NET預設錯誤頁
else if (testItem == "error")
throw new ApplicationException("故意錯誤");
//測試4, 抛回Client端可解讀的HTTP 500
else if (testItem == "errorInfo")
{
Response.StatusCode = 500;
Response.Write("我達達的馬蹄是個美麗的錯誤~");
}
Response.End();
}
}
</script>
<!DOCTYPE>
<html>
<head id="Head1" runat="server">
<title>AJAX Example</title>
<style>
body,input { font-size: 9pt; }
</style>
<script src='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.js'></script>
<script>
$(function () {
$("#btnGet").click(function () {
$("#frmShow").attr("src",
"?test=" + $("#selTestItem").val());
});
$("#btnAjax").click(function () {
var test = $("#selTestItem").val();
var $disp = $("#dvStatus");
$disp.text("");
$.ajax({
url: "?test=" + test,
//測試method時使用DELETE,其餘時候傳回P
type: test == "method" ? "DELETE" : "POST",
contentType: "application/json; charset=UTF-8",
statusCode: { //依不同StatusCode執行不同邏輯
200: function (r) { alert("OK-" + r); },
201: function (res, stausText, xhr) {
alert("201-Location=" +
//透過XHR取出Response Header
xhr.getResponseHeader("Location"));
},
404: function () {
alert("Page Not Found!");
},
500: function (xhr, statusText, err) {
alert(xhr.responseText);
}
},
error: function (xhr, statusText, err) {
//StatusCode=2xx或304時執行success, 其餘則將觸發error
$disp.text("ERROR->" + statusText + "/" + err);
}
});
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
測試項目:
<select id="selTestItem">
<option value="method">DELETE Method</option>
<option value="404">傳回404</option>
<option value="201">傳回201及Header</option>
<option value="error">發生錯誤</option>
<option value="errorInfo">解析錯誤</option>
</select>
<input type="button" id="btnGet" value="直接瀏覽" />
<input type="button" id="btnAjax" value="AJAX存取" />
<hr />
<div id="dvStatus"></div>
<iframe id="frmShow" style="width: 350px; height: 300px"></iframe>
</form>
</body>
</html>
執行結果如下:
1) 用IFrame直接瀏覽?test=delete,無法指定HttpMethod,故HttpMethod==GET
2) 直接瀏覽?test=201,StatusCode=201與一般正常執行無異,也無法存取Location資訊
3) 直接瀏覽?test=404,如同一般找不到網頁的情境
4) 直接瀏覽?test=error,因未開web.config customError,故看到ASP.NET預設的錯誤畫面
5) 直接瀏覽?test=errorInfo,可看出網站出錯,但看不到額外傳回的訊息
6) 使用$.ajax() type: "DELETE",Server端成功解讀HttpMethod
7) $.ajax()攔截到statusCode 404,而頁面上<div id=”dvStatud”>顯示"ERROR->error/Not Found”,表示error: function()也被觸發了。
8) $.ajax()攔載到statusCode 201,也成功由Response Header取出Location資訊
9) $.ajax()接收ASP.NET例外網頁,error被觸發,但訊息內容為HTML,Client程式難以解析
10) Server端回傳StatusCode 500並Response.Write特定文字,$.ajax()偵錯到error且能讀取訊息
用$.ajax()搞定Client端呼叫REST的各項要求後,接下來就要回到主場ASP.NET 3.5迎接建立RESTful Web Service的挑戰囉~
Comments
Be the first to post a comment