使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【十】——使用CacheCow和ETag缓存资源

系列导航地址http://www.cnblogs.com/fzrain/p/3490137.htmlhtml

前言

本文将使用一个开源框架CacheCow来实现针对Http请求资源缓存,本文主要介绍服务器端的缓存。ios

使用缓存技术能够很好的提升Web Api的性能,减少服务器的开销。咱们把这种缓存形式称之为:条件化请求(Conditional Requests)。具体表现为:客户端向服务器请求时会附加一个请求头ETag,而后服务器会根据这个信息来决定是否须要把更新过的资源响应给客户端,若是须要,则响应200状态吗以及资源内容,不然响应304状态码(Not modified)以及一个空的响应正文。git

什么是ETag?

写了好多,那么什么是ETag呢?ETag是服务器为特定资源生成的一个惟一标识(string类型)。你也能够理解为用来检查服务器资源是否变化。github

ETag分2种类型:强类型和弱类型。对于弱类型的ETag包含一个前缀W(例如:W/53fsfsd322),而强类型的ETag不包含任何前缀(例如:53fsfsd322)。一般来讲,弱类型ETag表明缓存短期资源(内存缓存),而强类型的ETag缓存是靠持久化的方式来实现的。web

ETag工做原理

先上一张图:sql

webapicachingetag

由上图可知:在一开始,客户端发起一个Http Get请求,请求的是id为4的course资源,因为这个资源是第一次被访问,所以服务器在把资源返回的同时附加了一个响应头(ETag)。chrome

如今,客户端发送Http Get请求想要再次请求相同的资源(Course id: 4),考虑到客户端使用缓存,所以Get请求初始化的时候增长一个Header(If-None-Match),内容就是资源的ETag值。当服务器接受到请求的时候,就会读取ETag的值并与服务器内的ETag值作比较,若是彻底相同,服务器就会返回304状态码(Not modified)而且正文不含任何内容。这样客户端就知道资源是最新的。数据库

对于Http Get和Delete请求,咱们可使用(If-None-Match)头,但对于更新时咱们要使用(If-Match)来匹配Put/Patch请求。请求到达的时候,服务器会校验ETag值,若是不同,服务器就会响应一个412状态码(Precondition Failed),所以客户端就知道本身的版本不是最新的,在客户端没有获取最新资源以前是不容许更新的。api

在Web Api中配置CacheCow

通过了以前的一段简单介绍,咱们来实现所谓的“条件化请求”。缓存

咱们须要使用NuGet来安装CacheCow,打开NuGet控制台,输入“Install-Package CacheCow.Server -Version 0.4.12”。会安装2个dll:CacheCow.Server和CacheCow.Common。

配置CacheCow也是很是简单的,咱们所须要作的是建立一个Cache Handler并把它注入到web api的请求管道中。这个handler就是在请求到达和离开web api的时候检查ETag和生成ETag的。

为了实现这一点,在“WebApiConfig.cs”里作以下配置:

//Configure HTTP Caching using Entity Tags (ETags)
var cacheCowCacheHandler = new CacheCow.Server.CachingHandler();
config.MessageHandlers.Add(cacheCowCacheHandler);

到目前为止,咱们的web api已经具备使用本机内存实现缓存的功能了,这也是CacheCow默认的配置,在单机状态(只有一台服务器)的时候可谓是比较完美了。然而,当应用程序走向分布式的时候就出现为题了——因为不一样的web服务器须要共享缓存状态,所以咱们须要把缓存状态持久化到一个单独的地方(SQL Server, MongoDB, MemCache)。可是在实现持久化以前咱们先测试一下内存缓存。

打开咱们的测试客户端PostMan(chrome插件),发送Get请求到:http://localhost:{your_port}/api/courses/4

image

结果:

QQ截图20140322232345

请求注释:

1.响应Http状态码是200,意昧着服务器把资源一块儿响应过来了。

2.此次响应增长了2条头信息:ETag和Last-Modified,目前咱们只需关心ETag的值,由于下次请求会用到。

3.ETag的类型是弱类型的(带有W前缀),说明这个缓存存在于服务器的内存中,若是重启IIS或切断服务进程的话,缓存就会失效。

对于接受到ETag值的客户端,在下次请求相同资源的时候就须要附加一个“If-None-Match”的请求头,服务器就会比较客户端与本身内存中的ETag值,若是相同,返回304(Not modified),不相同则返回200加上资源内容。

测试:咱们再次请求这个资源

image

结果:

image

对于此次请求来讲:

1.http状态码是304,意味着客户端的资源是最新的,所以响应body是空的

2.客户端获得相同的ETag值

在SQL Server端实现缓存

在SQL Server中作缓存一样很简单,首先咱们要肯定在哪一个持久化介质中实现缓存,咱们用的是SQL Server,所以打开NuGet控制台,输入以下命令:Install-Package CacheCow.Server.EntityTagStore.SqlServer -Version 0.4.11。

而后在“WebApiConfig”作以下配置:

//Configure HTTP Caching using Entity Tags (ETags)
var connString = System.Configuration.ConfigurationManager.ConnectionStrings["eLearningConnection"].ConnectionString;
var eTagStore = new CacheCow.Server.EntityTagStore.SqlServer.SqlServerEntityTagStore(connString);
var cacheCowCacheHandler = new CacheCow.Server.CachingHandler(eTagStore);
cacheCowCacheHandler.AddLastModifiedHeader = false;
config.MessageHandlers.Add(cacheCowCacheHandler);

上面的实现很明显,CacheCow须要把缓存信息存到数据库中,所以咱们须要制定咱们api所用的数据库。而后把eTagStore实例赋给Cache handler。

若是你如今直接请求api的话,等待你的不是资源而是一个500错误码。这是由于以前咱们介绍到CacheCow须要把缓存信息存入数据库,那么数据库中就应该有一张对应的表以及操做这张表的存储过程,所以咱们须要执行一个sql脚本。这个脚本一般在“{projectpath}\packages\CacheCow.Server.EntityTagStore.SqlServer.0.4.11\script”

执行完这个脚本后,你会发现数据库多了一张表以及5个存储过程:

image

ok,能够测试了,仍是刚刚的例子:

image

QQ截图20140323001639

正如上图所示,ETag的值再也不是弱类型的了,所以咱们存到SQL Server中了,打开SQL Server中的CacheState表,你会发现:

image

如今,只要没有客户端来更新这个资源,以前访问过这个资源的客户端通通会获得304状态码以及空的body(前提是客户端的请求中包含ETag值,呵呵)。

如今咱们实现一下更新,客户端要更新资源就须要包含一个“If-Match”的请求头,以下图所示:

QQ截图20140323002910

结果:

image

ETag已经改变:

image

咱们使用老的ETag再次请求服务器:

QQ截图20140323002910

因此结果:

image

这个响应告诉客户端:”你手里的资源不是最新的,先拿到最新的资源我才让你修改”。

总结

拖了很久的最后一篇终于和你们见面了,主要都是一些理论,代码也就5行,不过感受ETag还真的挺强大的。

本次系列到这里也要告一段落了,不过以后还打算介绍一些有其余内容(包括Web Api 2的新特性IHttpActionResult,CORS的支持以及OData的支持等),敬请期待。。。

源码地址:https://github.com/fzrain/WebApi.eLearning

相关文章
相关标签/搜索