ASP.NET Web API 中傳送 HTML 表單資料: form-urlencoded 資料Sending HTML Form Data in ASP.NET Web API: Form-urlencoded Data

藉由Mike Wassonby Mike Wasson

第 1 部分: Form-urlencoded 資料Part 1: Form-urlencoded Data

本文說明如何發佈到 Web API 控制器的 form-urlencoded 資料。This article shows how to post form-urlencoded data to a Web API controller.

HTML 表單的概觀Overview of HTML Forms

HTML 表單使用取得,或是張貼到將資料傳送到伺服器。HTML forms use either GET or POST to send data to the server. 方法屬性表單項目提供的 HTTP 方法:The method attribute of the form element gives the HTTP method:

<form action="api/values" method="post">

預設方法是 GET。The default method is GET. 如果此表單會使用 GET,資料會被編碼為查詢字串之 URI 中的表單。If the form uses GET, the form data is encoded in the URI as a query string. 如果表單會使用 POST,表單資料被放在要求主體中。If the form uses POST, the form data is placed in the request body. 已張貼的資料,如enctype屬性會指定要求主體格式:For POSTed data, the enctype attribute specifies the format of the request body:

enctypeenctype 描述Description
application/x-www-form-urlencodedapplication/x-www-form-urlencoded 表單資料會編碼成名稱/值組,類似於 URI 查詢字串。Form data is encoded as name/value pairs, similar to a URI query string. 這是 POST 的預設格式。This is the default format for POST.
multipart/form-datamultipart/form-data 表單資料會編碼為多部分 MIME 訊息。Form data is encoded as a multipart MIME message. 如果您要將檔案上傳到伺服器,請使用此格式。Use this format if you are uploading a file to the server.

這篇文章的第 1 部分探討 x-www-表單-urlencoded 格式。Part 1 of this article looks at x-www-form-urlencoded format. 第 2 部分描述多部分 MIME。Part 2 describes multipart MIME.

傳送的複雜型別Sending Complex Types

一般而言,您將會傳送複雜型別,從數個表單控制項的值所組成。Typically, you will send a complex type, composed of values taken from several form controls. 請考慮下列模型表示的狀態更新:Consider the following model that represents a status update:

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; }
    }
}

以下是可接受的 Web API 控制器Update透過 POST 的物件。Here is a Web API controller that accepts an Update object via POST.

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}"。This controller uses action-based routing, so the route template is "api/{controller}/{action}/{id}". 用戶端會將資料公佈至"/api/updates/complex"。The client will post the data to "/api/updates/complex".

現在讓我們編寫 HTML 表單提交狀態更新的使用者。Now let's write an HTML form for users to submit a status update.

<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。Notice that the action attribute on the form is the URI of our controller action. 以下是表單中輸入一些值:Here is the form with some values entered in:

當使用者按一下送出時,瀏覽器會傳送 HTTP 要求如下所示:When the user clicks Submit, the browser sends an HTTP request similar to the following:

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

請注意要求主體包含表單資料,格式為名稱/值組。Notice that the request body contains the form data, formatted as name/value pairs. Web API 會自動轉換為名稱/值組的執行個體Update類別。Web API automatically converts the name/value pairs into an instance of the Update class.

透過 AJAX 的表單資料傳送Sending Form Data via AJAX

當使用者提交表單時,瀏覽器瀏覽離開目前頁面,並呈現回應訊息的本文。When a user submits a form, the browser navigates away from the current page and renders the body of the response message. 回應是 HTML 網頁時 [確定]。That's OK when the response is an HTML page. 使用 web API 中,不過,回應主體是通常是空的或包含結構化的資料,例如 JSON。With a web API, however, the response body is usually either empty or contains structured data, such as JSON. 在此情況下,較為合理,將傳送使用 AJAX 的表單資料要求,讓網頁可以處理回應。In that case, it makes more sense to send the form data using an AJAX request, so that the page can process the response.

下列程式碼顯示如何發佈使用 jQuery 表單資料。The following code shows how to post form data using 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提交函式會以新的函式取代為表單動作。The jQuery submit function replaces the form action with a new function. 這會覆寫 [提交] 按鈕的預設行為。This overrides the default behavior of the Submit button. 序列化函式會將表單資料序列化成名稱/值組。The serialize function serializes the form data into name/value pairs. 若要將表單資料傳送至伺服器中,呼叫$.post()To send the form data to the server, call $.post().

要求完成時,.success().error()處理常式會向使用者顯示適當的訊息。When the request completes, the .success() or .error() handler displays an appropriate message to the user.

傳送的簡單類型Sending Simple Types

在先前章節中,我們會傳送複雜型別,Web API 的還原序列化的模型類別的執行個體。In the previous sections, we sent a complex type, which Web API deserialized to an instance of a model class. 您也可以傳送簡單的型別,例如字串。You can also send simple types, such as a string.

注意

在傳送之前的簡單類型,請考慮改為包裝複雜型別中的值。Before sending a simple type, consider wrapping the value in a complex type instead. 這可讓您在伺服器端上的模型驗證的優點,並可讓您更輕鬆地擴充您的模型,如有需要。This gives you the benefits of model validation on the server side, and makes it easier to extend your model if needed.

基本的步驟,以傳送簡單的型別相同,但有兩個微妙的差異。The basic steps to send a simple type are the same, but there are two subtle differences. 首先,在控制器中,您必須裝飾的參數名稱前面加FromBody屬性。First, in the controller, you must decorate the parameter name with the FromBody attribute.

[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 中的簡單類型。By default, Web API tries to get simple types from the request URI. FromBody屬性會告知 Web API,可讀取的要求主體中的值。The FromBody attribute tells Web API to read the value from the request body.

注意

Web API 回應主體讀取最多一次,因此只有一個動作的參數可能來自要求主體。Web API reads the response body at most once, so only one parameter of an action can come from the request body. 如果您需要從要求主體中取得多個值,定義複雜型別。If you need to get multiple values from the request body, define a complex type.

第二,用戶端必須傳送的值,其格式如下:Second, the client needs to send the value with the following format:

=value

具體來說,名稱/值組的名稱部分必須是空的簡單型別。Specifically, the name portion of the name/value pair must be empty for a simple type. 並非所有瀏覽器都支援此 HTML 表單,但您建立此格式在指令碼,如下所示:Not all browsers support this for HTML forms, but you create this format in script as follows:

$.post('api/updates/simple', { "": $('#status1').val() });

以下是範例表單:Here is an example form:

<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>

而以下是要提交的表單值的指令碼。And here is the script to submit the form value. 先前的指令碼的唯一差別是傳入的引數張貼函式。The only difference from the previous script is the argument passed into the post function.

$('#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;
});

您可以使用相同的方法來傳送簡單類型的陣列:You can use the same approach to send an array of simple types:

$.post('api/updates/postlist', { "": ["update one", "update two", "update three"] });

其他資源Additional Resources

第 2 部分: 檔案上傳和多個 MIMEPart 2: File Upload and Multipart MIME