Web API中的内容协商

一、内容协商的概念

  HTTP规范将内容协商定义为“当有多个格式可用时为给定响应选择最佳格式的过程”。HTTP中内容协商的主要机制是这些请求标头:

Accept:响应可接受哪些媒体类型,例如“application / json”
Accept-Charset:可接受哪些字符集,例如UTF-8或ISO 8859-1。
Accept-Encoding:可接受哪些内容编码,例如gzip。
Accept-Language:首选的自然语言,例如“en-us”。

二、WebApi中序列化

如果Web API控制器将资源作为CLR类型返回,在管道将会将CLR类型序列化然后将其写入HTTP响应正文。

(一)直接返回一个CLR对象

public Product GetProduct(int id)
{
    var item = _products.FirstOrDefault(p => p.ID == id);
    if (item == null)
    {
    throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return item; 
}

客户端可能会发送此HTTP请求:

GET http://localhost.:21069/api/products/1 HTTP/1.1
Host: localhost.:21069
Accept: application/json, text/javascript, */*; q=0.01

作为响应,服务器可能会发送:

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}

  在这个栗子中,客户端请求JSON,Javascript或“任何”(* / *)。服务器使用Product对象的JSON表示进行响应。请注意,响应中的Content-Type标头设置为“application / json”

(二)控制器返回HttpResponseMessage对象

  控制器还可以返回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,"application/json");
}

  返回HttpResponseMessage时,我们可以更好地控制响应的详细信息。我们可以设置状态代码,添加HTTP标头,指定媒体格式等。

三、内容协商的工作原理

内容协商的工作过程可以分为两步:

第一步: 管道从HttpConfiguration对象获取IContentNegotiator服务 。

第二步: 从HttpConfiguration.Formatters集合中获取媒体格式化器列表 。

第三步: 管道调用IContentNegotiatior.Negotiate(type,request,famatters) 
  参数是:要序列化的对象类型,Request对象,媒体格式化器的集合
  返回结果:选用的格式化器,相应的媒体类型
如果未找到格式化器,则Negotiate方法返回null,并且客户端接收HTTP错误406(不可接受)。
控制器如何直接调用内容协商的栗子:

public HttpResponseMessage GetProduct(int id)
{
    var product = new Product() 
    { Id = id, Name = "Gizmo", Category = "Widgets", Price = 1.99M };

//获取IContentNegotiator的服务实例
    IContentNegotiator negotiator =     this.Configuration.Services.GetContentNegotiator();

//Negotiate返会媒体类型和选择的formatter
    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,                   // 序列化的对象
      result.Formatter,          // 采用的formmter
      result.MediaType.MediaType // 媒体类型
    )
  };
}     

如果想了解更多内容协商的内容,可以查看官网

猜你喜欢

转载自www.cnblogs.com/wyy1234/p/9480646.html