本文是Web API系列教程的第6.3小節javascript
摘自:http://www.asp.net/web-api/overview/formats-and-model-binding/content-negotiationhtml
By Mike Wasson|May 20, 2012
做者:Mike Wasson | 日期:2012-3-20java
This article describes how ASP.NET Web API implements content negotiation.
本文描述ASP.NET Web API如何實現內容協商。web
The HTTP specification (RFC 2616) defines content negotiation as 「the process of selecting the best representation for a given response when there are multiple representations available.」 The primary mechanism for content negotiation in HTTP are these request headers:
HTTP規範(RFC 2616)將內容協商定義爲「在有多個表現可用時,爲一個給定的響應選擇最佳表現的過程」。在HTTP中內容協商的主要機制是如下請求報頭:json
The server can also look at other portions of the HTTP request. For example, if the request contains an X-Requested-With header, indicating an AJAX request, the server might default to JSON if there is no Accept header.
服務器也能夠查看HTTP請求的其它選項。例如,若是該請求含有一個X-Requested-With報頭,它指示這是一個AJAX請求,在沒有Accept報頭的狀況下,服務器可能會默認使用JSON。api
In this article, we’ll look at how Web API uses the Accept and Accept-Charset headers. (At this time, there is no built-in support for Accept-Encoding or Accept-Language.)
本文將考察Web API如何使用Accept和Accept-Charset報頭。(目前,尚未對Accept-Encoding或Accept-Language的內建支持。)服務器
If a Web API controller returns a resource as CLR type, the pipeline serializes the return value and writes it into the HTTP response body.
若是Web API控制器返回一個CLR類型的響應,(請求處理)管線會對返回值進行序列化,並將其寫入HTTP響應體。app
For example, consider the following controller action:
例如,考慮如下控制器動做:asp.net
public Product GetProduct(int id) { var item = _products.FirstOrDefault(p => p.ID == id); if (item == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } return item; }
A client might send this HTTP request:
客戶端可能會發送這樣的HTTP請求:ide
GET http://localhost.:21069/api/products/1 HTTP/1.1 Host: localhost.:21069 Accept: application/json, text/javascript, */*; q=0.01
In response, the server might send:
服務器可能會發送如下響應:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 57 Connection: Close
{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}
In this example, the client requested either JSON, Javascript, or 「anything」 (*/*). The server responsed with a JSON representation of the Product object. Notice that the Content-Type header in the response is set to "application/json".
在這個例子中,客戶端請求(指定)了JSON、Javascript、或「任意格式(*/*)」。服務器以一個Product對象的JSON表示做出了響應。注意,響應中的Content-Type報頭已被設置成「application/json」。
A controller can also return an HttpResponseMessage object. To specify a CLR object for the response body, call the CreateResponse extension method:
控制器也能夠返回一個HttpResponseMessage對象。爲了指定響應體的CLR對象,要調用CreateResponse擴展方法(注意,如下代碼是控制器中的一個動做方法,不是整個控制器 — 譯者注):
public HttpResponseMessage GetProduct(int id) { var item = _products.FirstOrDefault(p => p.ID == id); if (item == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } return Request.CreateResponse(HttpStatusCode.OK, product); }
This option gives you more control over the details of the response. You can set the status code, add HTTP headers, and so forth.
該選項讓你可以對響應細節進行更多的控制。你能夠設置狀態碼、添加HTTP報頭等等。
The object that serializes the resource is called a media formatter. Media formatters derive from the MediaTypeFormatter class. Web API provides media formatters for XML and JSON, and you can create custom formatters to support other media types. For information about writing a custom formatter, see Media Formatters.
對資源進行序列化的對象叫作媒體格式化器(media formatter)。媒體格式化器派生於MediaTypeFormatter類。Web API提供了XML和JSON的媒體格式化器,於是你能夠建立自定義的格式化器,以支持其它媒體類型。更多關於編寫自定義格式化器的信息,請參閱「媒體格式化器(本系列教程的第6.1小節 — 譯者注)」。
First, the pipeline gets the IContentNegotiator service from the HttpConfiguration object. It also gets the list of media formatters from the HttpConfiguration.Formatters collection.
首先,管線會獲取HttpConfiguration對象的IContentNegotiator服務。它也會獲得HttpConfiguration.Formatters集合的媒體格式化器列表。
Next, the pipeline calls IContentNegotiatior.Negotiate, passing in:
接着,管線會調用IContentNegotiatior.Negotiate,在其中傳遞:
The Negotiate method returns two pieces of information:
Negotiate方法返回兩個信息片斷:
If no formatter is found, the Negotiate method returns null, and the client recevies HTTP error 406 (Not Acceptable).
若是未找到格式化器,方法返回null,而客戶端會接收到一個HTTP的406(不可接收的)錯誤。
The following code shows how a controller can directly invoke content negotiation:
如下代碼展現了控制器如何纔可以直接調用內容協商:
public HttpResponseMessage GetProduct(int id) { var product = new Product() { Id = id, Name = "Gizmo", Category = "Widgets", Price = 1.99M };
IContentNegotiator negotiator = this.Configuration.Services.GetContentNegotiator();
ContentNegotiationResult result = negotiator.Negotiate( typeof(Product), this.Request, this.Configuration.Formatters); if (result == null) { var response = new HttpResponseMessage(HttpStatusCode.NotAcceptable); throw new HttpResponseException(response)); }
return new HttpResponseMessage() { Content = new ObjectContent<Product>( product, // What we are serializing(序列化什麼) result.Formatter, // The media formatter(媒體格式化器 result.MediaType.MediaType // The MIME type(MIME類型) ) }; }
This code is equivalent to the what the pipeline does automatically.
上述代碼等價於管線的自動完成
The DefaultContentNegotiator class provides the default implementation of IContentNegotiator. It uses several criteria to select a formatter.
DefaultContentNegotiator類提供了IContentNegotiator的默認實現。它使用了幾個選擇格式化器的條件。
First, the formatter must be able to serialize the type. This is verified by calling MediaTypeFormatter.CanWriteType.
首先,格式化器必須可以對類型進行序列化,這是經過MediaTypeFormatter.CanWriteType來檢驗的。
Next, the content negotiator looks at each formatter and evaluates how well it matches the HTTP request. To evaluate the match, the content negotiator looks at two things on the formatter:
其次,內容協商器要考查每一個格式化器,並評估此格式化器與HTTP請求的匹配好壞。爲了評估匹配狀況,內容協商器要對此格式化器考察兩樣東西:
If there are multiple matches, the match with the highest quality factor wins. For example:
若是有多個匹配,帶有最高質量因子的匹配獲勝。例如:
Accept: application/json, application/xml; q=0.9, */*; q=0.1
In this example, application/json has an implied quality factor of 1.0, so it is preferred over application/xml.
在這個例子中,application/json具備隱含的質量因子1.0,所以它優於application/xml。
If no matches are found, the content negotiator tries to match on the media type of the request body, if any. For example, if the request contains JSON data, the content negotiator looks for a JSON formatter.
若是未找到匹配,內容協商器會嘗試匹配請求體的媒體類型(有請求體時)。例如,若是請求含有JSON數據,內容協商器會找到JSON格式化器。
If there are still no matches, the content negotiator simply picks the first formatter that can serialize the type.
若是仍無匹配,內容協商器便簡單地撿取可以對類型進行序列化的第一個格式化器。
After a formatter is selected, the content negotiator chooses the best character encoding. by looking at the SupportedEncodings property on the formatter, and matching it against the Accept-Charset header in the request (if any).
在選擇格式化器以後,內容協商器會選擇最佳字符編碼。經過考察格式化器的SupportedEncodings,並根據請求的報送對其進行匹配(若是有)。
看完此文若是以爲有所收穫,請給個推薦。 你的推薦是我繼續下去的動力,也會讓更多人關注並獲益,這也是你的貢獻。