傳送 ASP.NET Web API 的 HTML 表單資料:Form-urlencoded 資料
第 1 部分:Form-urlencoded 資料
本文說明如何將 form-urlencoded 資料發佈至 Web API 控制器。
注意
HTML 表單概觀
HTML 表單會使用 GET 或 POST 將資料傳送至伺服器。 form 項目的 method 屬性提供了 HTTP方法:
<form action="api/values" method="post">
預設方法為 GET。 如果表單使用 GET,表單資料會在 URI 中編碼為查詢字串。 如果表單使用 POST,表單資料會放在要求本文中。 針對 POSTed 資料,enctype 屬性會指定要求本文的格式:
enctype | 描述 |
---|---|
application/x-www-form-urlencoded | 表單資料會編碼為名稱/值組,類似於 URI 查詢字串。 這是 POST 的預設格式。 |
multipart/form-data | 表單資料會編碼為多部分 MIME 訊息。 如果您要將檔案上傳至伺服器,請使用此格式。 |
本文的第 1 部分會探討 x-www-form-urlencoded 格式。 第 2 部分說明多部分 MIME。
傳送複雜類型
一般而言,您會傳送複雜類型,由數個表單控制項取用的值所組成。 請考慮下列代表狀態更新的模型:
namespace FormEncode.Models
{
using System;
using System.ComponentModel.DataAnnotations;
public class Update
{
[Required]
[MaxLength(140)]
public string Status { get; set; }
public DateTime Date { get; set; }
}
}
以下是可透過 POST 接受 Update
物件的 Web API 控制器。
namespace FormEncode.Controllers
{
using FormEncode.Models;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
public class UpdatesController : ApiController
{
static readonly Dictionary<Guid, Update> updates = new Dictionary<Guid, Update>();
[HttpPost]
[ActionName("Complex")]
public HttpResponseMessage PostComplex(Update update)
{
if (ModelState.IsValid && update != null)
{
// Convert any HTML markup in the status text.
update.Status = HttpUtility.HtmlEncode(update.Status);
// Assign a new ID.
var id = Guid.NewGuid();
updates[id] = update;
// Create a 201 response.
var response = new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent(update.Status)
};
response.Headers.Location =
new Uri(Url.Link("DefaultApi", new { action = "status", id = id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
[HttpGet]
public Update Status(Guid id)
{
Update update;
if (updates.TryGetValue(id, out update))
{
return update;
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
}
}
注意
此控制器會使用 動作型路由,因此路由範本為「api/{controller}/{action}/{id}」。 用戶端會將資料發佈至「/api/updates/complex」。
現在讓我們撰寫 HTML 表單,讓使用者提交狀態更新。
<h1>Complex Type</h1>
<form id="form1" method="post" action="api/updates/complex"
enctype="application/x-www-form-urlencoded">
<div>
<label for="status">Status</label>
</div>
<div>
<input name="status" type="text" />
</div>
<div>
<label for="date">Date</label>
</div>
<div>
<input name="date" type="text" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
請注意,表單上的 動作屬性是控制器動作的 URI。 以下是輸入一些值的表單:
當使用者按一下 [提交] 時,瀏覽器會傳送類似下列的 HTTP 要求:
POST http://localhost:38899/api/updates/complex HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
status=Shopping+at+the+mall.&date=6%2F15%2F2012
請注意,要求本文包含表單資料,格式為名稱/值組。 Web API 會自動將名稱/值組轉換成 Update
類別的執行個體。
透過 AJAX 傳送表單資料
當使用者提交表單時,瀏覽器會離開目前的頁面,並轉譯回應訊息的本文。 當回應是 HTML 頁面時,這是可以的。 不過,使用 Web API 時,回應本文通常是空的,或包含結構化資料,例如 JSON。 在此情況下,使用 AJAX 要求傳送表單資料更合理,讓頁面可以處理回應。
下列程式碼示範如何使用 jQuery 發佈表單資料。
<script type="text/javascript">
$("#form1").submit(function () {
var jqxhr = $.post('api/updates/complex', $('#form1').serialize())
.success(function () {
var loc = jqxhr.getResponseHeader('Location');
var a = $('<a/>', { href: loc, text: loc });
$('#message').html(a);
})
.error(function () {
$('#message').html("Error posting the update.");
});
return false;
});
</script>
jQuery 提交函式以新函式取代了表單動作。 這會覆寫 [提交] 按鈕的預設行為。 序列化函式會將表單資料序列化成名稱/值組。 若要將表單資料傳送到伺服器,請呼叫 $.post()
。
當要求完成時,.success()
或 .error()
處理常式會向使用者顯示適當的訊息。
傳送簡單類型
在前幾節中,我們傳送了複雜類型,Web API 已還原序列化至模型類別的執行個體。 您也可以傳送簡單的類型,例如字串。
注意
傳送簡單類型之前,請考慮改為將值包裝在複雜類型中。 這可讓您在伺服器端取得模型驗證的優點,並在需要時更輕鬆地擴充模型。
傳送簡單類型的基本步驟相同,但有兩個細微的差異。 首先,在控制器中,您必須使用 FromBody 屬性裝飾參數名稱。
[HttpPost]
[ActionName("Simple")]
public HttpResponseMessage PostSimple([FromBody] string value)
{
if (value != null)
{
Update update = new Update()
{
Status = HttpUtility.HtmlEncode(value),
Date = DateTime.UtcNow
};
var id = Guid.NewGuid();
updates[id] = update;
var response = new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent(update.Status)
};
response.Headers.Location =
new Uri(Url.Link("DefaultApi", new { action = "status", id = id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
根據預設,Web API 會嘗試從要求 URI 取得簡單類型。 FromBody 屬性會指示 Web API 從要求本文讀取值。
注意
Web API 最多一次讀取回應本文,因此只有一個動作參數可以來自要求本文。 如果您需要從要求本文取得多個值,請定義複雜類型。
其次,客戶端必須以下列格式傳送值:
=value
具體來說,名稱/值組的名稱部分必須是空的簡單類型。 並非所有瀏覽器都支援 HTML 表單,但您可以在指令碼中建立此格式,如下所示:
$.post('api/updates/simple', { "": $('#status1').val() });
以下是範例表單:
<h1>Simple Type</h1>
<form id="form2">
<div>
<label for="status">Status</label>
</div>
<div>
<input id="status1" type="text" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
以下是提交表單值的指令碼。 與上一個指令碼的唯一差異是傳遞至 post 函式的引數。
$('#form2').submit(function () {
var jqxhr = $.post('api/updates/simple', { "": $('#status1').val() })
.success(function () {
var loc = jqxhr.getResponseHeader('Location');
var a = $('<a/>', { href: loc, text: loc });
$('#message').html(a);
})
.error(function () {
$('#message').html("Error posting the update.");
});
return false;
});
您可以使用相同的方法來傳送簡單類型的陣列:
$.post('api/updates/postlist', { "": ["update one", "update two", "update three"] });