本文是Web API系列教程的第6.3小节

6.3 Content Negotiation
6.3 内容协商

摘自:http://www.asp.net/web-api/overview/formats-and-model-binding/content-negotiation

By Mike Wasson|May 20, 2012
作者:Mike Wasson | 日期:2012-3-20

This article describes how ASP.NET Web API implements content negotiation.
本文描述ASP.NET Web API如何实现内容协商。

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中内容协商的主要机制是以下请求报头:

  • Accept: Which media types are acceptable for the response, such as “application/json,” “application/xml,” or a custom media type such as "application/vnd.example+xml"
    Accept:响应可接收的媒体类型,如“application/json”、“application/xml”,或者自定义媒体类型,如“application/vnd.example+xml”。
  • Accept-Charset: Which character sets are acceptable, such as UTF-8 or ISO 8859-1.
    Accept-Charset:可接收的字符集,如“UTF-8”或“ISO 8859-1”。
  • Accept-Encoding: Which content encodings are acceptable, such as gzip.
    Accept-Encoding:可接收的内容编码,如“gzip”。
  • Accept-Language: The preferred natural language, such as “en-us”.
    Accept-Language:优先选用的自然语言,如“en-us”。

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。

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的内建支持。)

6.3.1 Serialization
6.3.1 序列化

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响应体。

For example, consider the following controller action:
例如,考虑以下控制器动作:

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请求:

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小节 — 译者注)”。

6.3.2 How Content Negotiation Works
6.3.2 内容协商的工作机制

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 type of object to serialize
    要序列化的对象类型
  • The collection of media formatters
    媒体格式化器集合
  • The HTTP request
    HTTP请求

The Negotiate method returns two pieces of information:
Negotiate方法返回两个信息片段:

  • Which formatter to use
    要使用的格式化器
  • The media type for the response
    用于响应的媒体类型

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.
上述代码等价于管线的自动完成

6.3.3 Default Content Negotiator
6.3.3 默认的内容协商器

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请求的匹配好坏。为了评估匹配情况,内容协商器要对此格式化器考察两样东西:

  • The SupportedMediaTypes collection, which contains a list of supported media types. The content negotiator tries to match this list against the request Accept header. Note that the Accept header can include ranges. For example, “text/plain” is a match for text/* or */*.
    SupportedMediaTypes集合,它含有一个可支持的媒体类型的列表。内容协商器尝试根据请求的Accept报头对这个列表进行匹配。注意,Accept报头可以包括范围。例如,“text/plain”可匹配“text/*”或“*/*”
  • The MediaTypeMappings collection, which contains a list of MediaTypeMapping objects. The MediaTypeMapping class provides a generic way to match HTTP requests with media types. For example, it could map a custom HTTP header to a particular media type.
    MediaTypeMappings集合,它含有对象一个MediaTypeMapping的对象列表。MediaTypeMapping类提供了一种泛型方式,以匹配带有媒体类型的HTTP请求。例如,它可以将一个自定义的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.
如果仍无匹配,内容协商器便简单地捡取能够对类型进行序列化的第一个格式化器。

6.3.4 Selecting a Character Encoding
6.3.4 选择字符编码

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,并根据请求的报送对其进行匹配(如果有)。

看完此文如果觉得有所收获,请给个推荐
你的推荐是我继续下去的动力,也会让更多人关注并获益,这也是你的贡献。

【ASP.NET Web API教程】6.3 内容协商的更多相关文章

  1. 【ASP.NET Web API教程】4.3 ASP.NET Web API中的异常处理

    原文:[ASP.NET Web API教程]4.3 ASP.NET Web API中的异常处理 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内 ...

  2. 【ASP.NET Web API教程】6 格式化与模型绑定

    原文:[ASP.NET Web API教程]6 格式化与模型绑定 6 Formats and Model Binding 6 格式化与模型绑定 本文引自:http://www.asp.net/web- ...

  3. 【ASP.NET Web API教程】3.2 通过.NET客户端调用Web API(C#)

    原文:[ASP.NET Web API教程]3.2 通过.NET客户端调用Web API(C#) 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的 ...

  4. 【ASP.NET Web API教程】3 Web API客户端

    原文:[ASP.NET Web API教程]3 Web API客户端 Chapter 3: Web API Clients 第3章 Web API客户端 本文引自:http://www.asp.net ...

  5. 【ASP.NET Web API教程】2.4 创建Web API的帮助页面

    原文:[ASP.NET Web API教程]2.4 创建Web API的帮助页面 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 2.4 ...

  6. 【ASP.NET Web API教程】2.3.7 创建首页

    原文:[ASP.NET Web API教程]2.3.7 创建首页 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 7: Crea ...

  7. 【ASP.NET Web API教程】2.3.6 创建产品和订单控制器

    原文:[ASP.NET Web API教程]2.3.6 创建产品和订单控制器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 6 ...

  8. 【ASP.NET Web API教程】2.3.5 用Knockout.js创建动态UI

    原文:[ASP.NET Web API教程]2.3.5 用Knockout.js创建动态UI 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容 ...

  9. 【ASP.NET Web API教程】2.3.4 创建Admin视图

    原文:[ASP.NET Web API教程]2.3.4 创建Admin视图 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 4: ...

  10. 【ASP.NET Web API教程】2.3.3 创建Admin控制器

    原文:[ASP.NET Web API教程]2.3.3 创建Admin控制器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 3 ...

随机推荐

  1. 【转载】C++ function、bind和lambda表达式

    本篇随笔为转载,原贴地址:C++ function.bind和lambda表达式. 本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lambda表达式, function对象和bind机制 ...

  2. asp.net C# 未能加载文件或程序集或它的某一个依赖项。需要强名称程序集。的解决办法

    asp.net C# 未能加载文件或程序集或它的某一个依赖项.需要强名称程序集.的解决办法 出现这个错误是原因:是有签名的DLL引用了无签名的DLL 如上图所示,就是因为引用Entity.MVCEnt ...

  3. iOS学习笔记(5)— UITextField

    UITextField详解 一.基本属性 1.创建文本输入框 UITextField*textField=[[UITextField alloc]initWithFrame:CGRectMake(10 ...

  4. ORACLE object_id和data_object_id

    object_id和data_object_id 都是对象的唯一标识. object_id是对象的逻辑标识 data_object_id是对象的物理标识 对于没有物理存储的对象,data_object ...

  5. firefox广告拦截插件

    firefox广告拦截插件: Adblock Plus  Adblock Edge Adblock Plus Pop-up Addon 如果不能更新,则需要修改HOST: 117.18.232.191 ...

  6. CF(协同过滤算法)

    1 集体智慧和协同过滤 1.1 什么是集体智慧(社会计算)? 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web ...

  7. SQL数据库完全复制

    很少摸 Windows 环境下的东西,最近被个 MS SQL Server 的数据库搞得头大.实在不像 MySQL 那样用起来轻车熟路, OrZ ... 本来以为企业管理器里面既然提供了 DTS 数据 ...

  8. 三级设置页面管理测试demo

    #include "PhoneBookWindow.h"#include "xWindow/xWindow.h"#include "hardwareD ...

  9. 第六章 springboot + 事务

    在实际开发中,其实很少会用到事务,一般情况下事务用的比较多的是在金钱计算方面. mybatis与spring集成后,其事务该怎么做?其实很简单,直接在上一节代码的基础上在相应的方法(通常是servic ...

  10. Median of Two Sorted Arrays

    题目:https://leetcode.com/problems/median-of-two-sorted-arrays/ 算法分析 这道题的目的,是为了从两个有序列中找到合并序列之后的中位数,即两个 ...