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

时间:2021-12-03 06:19:16

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

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

前言

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

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

什么是ETag?

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

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

ETag工作原理

先上一张图:

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

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

现在,客户端发送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),因此客户端就知道自己的版本不是最新的,在客户端没有获取最新资源之前是不允许更新的。

在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

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

结果:

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

请求注释:

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

2.这次响应增加了2条头信息:ETag和Last-Modified,目前我们只需关心ETag的值,因为下次请求会用到。

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

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

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

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

结果:

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

对于这次请求来说:

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个存储过程:

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

ok,可以测试了,还是刚刚的例子:

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

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

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

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

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

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

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

结果:

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

ETag已经改变:

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

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

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

所以结果:

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

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

总结

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

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

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

 

ASP.NET Web Api构建基于REST风格的服务实战系列教程的更多相关文章

  1. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】

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

  2. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【九】——API变了,客户端怎么办?

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 一旦我们将API发布之后,消费者就会开始使用并和其他的一些数据混在一起.然而,当新的需求出现 ...

  3. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这一篇文章我们主要来探讨一下Web Api的安全性,到目前为止所有的请求都是走的Http协议 ...

  4. [转]使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

    本文转自:http://www.cnblogs.com/fzrain/p/3552423.html 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html ...

  5. 使用ASP.NET WEB API构建基于REST风格的服务实战系列教程(一)——使用EF6构建数据库及模型

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 使用Entity Framework Code First模式构建数据库对象 已经决定使用EF C ...

  6. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【二】——使用Repository模式构建数据库访问层

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在数据访问层应用Repository模式来隔离对领域对象的细节操作是很有意义的.它位于映射层 ...

  7. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【三】——Web Api入门

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 经过前2节的介绍,我们已经把数据访问层搭建好了,从本章开始就是Web Api部分了.在正式开 ...

  8. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【四】——实现模型工厂,依赖注入以及格式配置

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在上一篇中,我们已经初步开始使用Web Api了,但同时出现了一些很多不足之处,本章我们就着 ...

  9. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...

随机推荐

  1. SuperMap-iServer-单点登录功能验证(CAS)

    SuperMap-iServer-单点登录功能验证(CAS) 1.测试目的: 验证SuperMap-iServer使用CAS单点登录的功能是否正常. 2.测试环境: SuperMap-iServer8 ...

  2. Rss 订阅:php动态生成xml格式的rss文件

    Rss 简介: 简易信息聚合(也 叫聚合内容)是一种描述和同步网站内容的格式.使用RSS订阅能更快地获取信息,网站提供RSS输出,有利于让用户获取网站内容的最新更新.网络用户可以在客户端借助于支持RS ...

  3. RPC通信框架——RCF介绍

    现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实现跨平台,支持Linux系统,以及后续的分布式,首要任务是去除COM接口. ...

  4. linux下motion摄像头监控编译与配置

    利用linxu下的开源的motion搭建嵌入式视频动态监控系统 所谓移动图像监测,简单来说就是利用摄像头定点监测某个区域,当有移动物体经过时,摄像头便自动抓拍(要监测多大物体.按拍照速率都是可调的), ...

  5. HTTP 无法注册 URL http://+:9999/CalculatorService/。进程不具有此命名空间的访问权限

    转自:http://www.cnblogs.com/flyher/archive/2013/06/28/3161170.html 写WCF时在 1 host.Open(); 报错:HTTP 无法注册 ...

  6. Chapter 21_5.1 URL编码

    URL编码是http所使用的一种编码方式,用于在一个URL中传送各种参数.该编码方式会将特殊字符("=","&","+")编码为&q ...

  7. UIKit控件直接显示网页文字内容

    NSString *html = @"<bold>Hello</bold> Now<br> <em>iOS</em> can cr ...

  8. Android时遇到R&period;java was modified manually&excl; Reverting to generated version&excl;

    欢迎关注公众号,每天推送Android技术文章,二维码如下:(可扫描) 进入 eclipse后clipse Menu >Projects > clean 这么做就把R文件删了,但是别担心, ...

  9. 自定义用户认证(继承django的)

    1.在app下创建一个自己用户认证文件,文件名随意,记得为.py文件 2.编辑该userauth.py文件 #!/usr/bin/env python #coding:utf-8 from djang ...

  10. &lbrack;Robot Framework&rsqb; Robot Framework里面的变量怎么知道是在哪里定义的?

    看变量在哪里定义的:Ctrl+Alt+Space