前言

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html

本文描述ASP.NET Web API如何实现内容协商。

HTTP规范(RFC 2616)将内容协商定义为“在有多个表现可用时,为一个给定的响应选择最佳表现的过程”。在HTTP中内容协商的主要机制是以下请求报头:

  • Accept:响应可接收的媒体类型,如“application/json”、“application/xml”,或者自定义媒体类型,如“application/vnd.example+xml”。
  • Accept-Charset:可接收的字符集,如“UTF-8”或“ISO 8859-1”。
  • Accept-Encoding:可接收的内容编码,如“gzip”。
  • Accept-Language:优先选用的自然语言,如“en-us”。

服务器也可以查看HTTP请求的其它选项。例如,如果该请求含有一个X-Requested-With报头,它指示这是一个AJAX请求,在没有Accept报头的情况下,服务器可能会默认使用JSON。

本文将考察Web API如何使用Accept和Accept-Charset报头。(目前,还没有对Accept-Encoding或Accept-Language的内建支持。)

Serialization——序列化

如果Web API控制器返回一个CLR类型的响应,(请求处理)管线会对返回值进行序列化,并将其写入HTTP响应体。

例如,考虑以下控制器动作:

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对象。为了指定响应体的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);
}

该选项让你能够对响应细节进行更多的控制。你可以设置状态码、添加HTTP报头等等。

对资源进行序列化的对象叫做媒体格式化器。媒体格式化器派生于MediaTypeFormatter类。Web API提供了XML和JSON的媒体格式化器,因而你可以创建自定义的格式化器,以支持其它媒体类型。更多关于编写自定义格式化器的信息 http://www.cnblogs.com/aehyok/p/3460164.html。

内容协商的工作机制

首先,管线会获取HttpConfiguration对象的IContentNegotiator服务。它也会得到HttpConfiguration.Formatters集合的媒体格式化器列表。

接着,管线会调用IContentNegotiatior.Negotiate,在其中传递:

  • 要序列化的对象类型
  • 媒体格式化器集合
  • HTTP请求

Negotiate方法返回两个信息片段:

  • 要使用的格式化器
  • 用于响应的媒体类型

如果未找到格式化器,方法返回null,而客户端会接收到一个HTTP的406(不可接收的)错误。

以下代码展示了控制器如何才能够直接调用内容协商:

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类型)
        )};
}

上述代码等价于管线的自动完成。

默认的内容协定

DefaultContentNegotiator类提供了IContentNegotiator的默认实现。它使用了几个选择格式化器的条件。

首先,格式化器必须能够对类型进行序列化,这是通过MediaTypeFormatter.CanWriteType来检验的。

其次,内容协商器要考查每个格式化器,并评估此格式化器与HTTP请求的匹配好坏。为了评估匹配情况,内容协商器要对此格式化器考察两样东西:

  • SupportedMediaTypes集合,它含有一个可支持的媒体类型的列表。内容协商器尝试根据请求的Accept报头对这个列表进行匹配。注意,Accept报头可以包括范围。例如,“text/plain”可匹配“text/*”或“*/*”
  • MediaTypeMappings集合,它含有对象一个MediaTypeMapping的对象列表。MediaTypeMapping类提供了一种泛型方式,以匹配带有媒体类型的HTTP请求。例如,它可以将一个自定义的HTTP报头映射到一个特定的媒体类型。

如果有多个匹配,带有最高质量因子的匹配获胜。例如:

Accept: application/json, application/xml; q=0.9, */*; q=0.1

在这个例子中,application/json具有隐含的质量因子1.0,因此它优于application/xml。

如果未找到匹配,内容协商器会尝试匹配请求体的媒体类型(有请求体时)。例如,如果请求含有JSON数据,内容协商器会找到JSON格式化器。

如果仍无匹配,内容协商器便简单地捡取能够对类型进行序列化的第一个格式化器。

选择字符编码

在选择格式化器之后,内容协商器会选择最佳字符编码。通过考察格式化器的SupportedEncodings,并根据请求的报送对其进行匹配(如果有)。

Asp.Net Web API 2第十四课——Content Negotiation(内容协商)相关推荐

  1. (四)Asp.net web api中的坑-【api的返回值】

    (四)Asp.net web api中的坑-[api的返回值] 原文:(四)Asp.net web api中的坑-[api的返回值] void无返回值 IHttpActionResult HttpRe ...

  2. ASP.NET MVC (四、ASP.NET Web API应用程序与跨域操作)

    目录 前言: 1.创建MVC项目 2.修改返回格式 3.创建[Web API]控制器 4.创建[HttpGet]访问接口 5.创建[HttpPost]访问接口 6.测试接口: 6.1.执行:点击[调试 ...

  3. Asp.Net Web API(四)

    HttpResponseException-----HTTP响应异常 如果Web API控制器抛出一个未捕捉的异常,会发生什么呢?在默认情况下,大多数异常都会转换为一个带有状态码500的内部服务器错误 ...

  4. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程

    最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tuto ...

  5. ASP.NET Web API 过滤器创建、执行过程(二)

    ASP.NET Web API 过滤器创建.执行过程(二) 前言 前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器 ...

  6. 【转】在ASP.NET Web API 2中使用Owin基于Token令牌的身份验证

    基于令牌的身份验证 基于令牌的身份验证主要区别于以前常用的基于cookie的身份验证,基于cookie的身份验证在B/S架构中使用比较多,但是在Web Api中因其特殊性,基于cookie的身份验证已 ...

  7. ASP.NET Web API的Controller是如何被创建的?

    Web API调用请求的目标是定义在某个HttpController类型中的某个Action方法,所以消息处理管道最终需要激活目标HttpController对象.调用请求的URI会携带目标HttpC ...

  8. ASP.net Web API综合示例

    目录 概述 功能介绍 程序结构 服务器端介绍 客户端介绍 "契约" Web API设计规则 并行写入冲突与时间戳 身份验证详解 Web API验证规则 客户端MVVM简介 Web. ...

  9. Asp.Net Web Api 部署------在云服务器IIS上部署Web Api程序

    Asp.Net Web Api 部署------在云服务器IIS上部署Web Api程序 本人Web Api程序框架选择的是.Net 5.0 一.在服务器上安装运行时RunTime,.Net 5 运行 ...

  10. ASP.NET Web API入门介绍(一)

    随着项目的复杂度越来越高,各种第三方系统的数据交互也越来越频繁,不可避免的就要用到Web API接口,这里Web API是一个比较宽泛的概念.本文提到Web API特指ASP.NET Web API. ...

最新文章

  1. 杂谈 - 开始认认真真写博客了
  2. 页面的前进/后退/刷新方法
  3. Angular2+ 结构型指令
  4. 基于神经网络的实体识别和关系抽取联合学习 | PaperWeekly #54
  5. Vue 路由router的两种模式
  6. DDNS For RHEL5
  7. 【九】Git 可视化GUI管理工具 - SourceTree
  8. java 注册成功跳转,写了个注册页面填了注册信息后点注册按钮居然不跳转,为什么?...
  9. Android 系统(144)---整包升级与差分升级的区别
  10. 数据库的一些基础研究和性能探讨(触发器)
  11. Codeforces Round #460 (Div. 2): D. Substring(有向图)
  12. 内卷严重?给程序员的几条建议
  13. 删除了项目下的\WEB-INF\classes文件夹,在eclipse的tomcat部署启动时报错。
  14. 计算机联锁人工进路的办理,计算机联锁与6502
  15. 虚拟机(VMWARE)安装的系统如何访问本地磁盘
  16. 基于CC2430的基础实验5---时钟模式
  17. SAI绘制神秘人教程
  18. 笔记本不小心网络重置后,不能上网,网络适配器存在感叹号
  19. 常见的几种最优化方法(梯度下降法、牛顿法、拟牛顿法、共轭梯度法等)
  20. 对populate()方法的理解

热门文章

  1. 使用C# Detach和Attach 数据库
  2. 微信支付 第一次成功,其他无法调起,返回-1(Android eclipse 微信支付之大坑 签名工具问题)
  3. iOS 代码命名规范 及Android 代码命名规范(2)Android
  4. [asp.net]优化ViewState
  5. PIL库的总结与简单应用
  6. Swift3.0朝圣之路-Then协议库-绝妙的初始化方式
  7. C#获取堆栈信息,输出文件名、行号、函数名、列号等
  8. Nginx 进程间通信
  9. 周记【距gdoi:105天】
  10. php字符编码转换问题