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

简介: 原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【十】——使用CacheCow和ETag缓存资源系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 本文将使用一个开源框架CacheCow来实现针对Http请求资源缓存,本文主要介绍服务器端的缓存。
原文: 使用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工作原理

先上一张图:

webapicachingetag

由上图可知:在一开始,客户端发起一个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

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

目录
相关文章
|
6月前
|
前端开发 JavaScript 开发者
JavaScript:构建动态Web的核心力量
JavaScript:构建动态Web的核心力量
|
10月前
|
前端开发 算法 API
构建高性能图像处理Web应用:Next.js与TailwindCSS实践
本文分享了构建在线图像黑白转换工具的技术实践,涵盖技术栈选择、架构设计与性能优化。项目采用Next.js提供优秀的SSR性能和SEO支持,TailwindCSS加速UI开发,WebAssembly实现高性能图像处理算法。通过渐进式处理、WebWorker隔离及内存管理等策略,解决大图像处理性能瓶颈,并确保跨浏览器兼容性和移动设备优化。实际应用案例展示了其即时处理、高质量输出和客户端隐私保护等特点。未来计划引入WebGPU加速、AI增强等功能,进一步提升用户体验。此技术栈为Web图像处理应用提供了高效可行的解决方案。
|
5月前
|
缓存 并行计算 监控
vLLM 性能优化实战:批处理、量化与缓存配置方案
本文深入解析vLLM高性能部署实践,揭秘如何通过continuous batching、PagedAttention与前缀缓存提升吞吐;详解批处理、量化、并发参数调优,助力实现高TPS与低延迟平衡,真正发挥vLLM生产级潜力。
1128 0
vLLM 性能优化实战:批处理、量化与缓存配置方案
|
6月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
286 1
Redis专题-实战篇二-商户查询缓存
|
8月前
|
存储 缓存 安全
Go语言实战案例-LRU缓存机制模拟
本文介绍了使用Go语言实现LRU缓存机制的方法。LRU(最近最少使用)是一种常见缓存淘汰策略,当缓存满时,优先删除最近最少使用的数据。实现中使用哈希表和双向链表结合的方式,确保Get和Put操作均在O(1)时间内完成。适用于Web缓存、数据库查询优化等场景。
|
9月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:使用 Gin 快速构建 Web 服务
Gin 是一个高效、轻量级的 Go 语言 Web 框架,支持中间件机制,非常适合开发 RESTful API。本文从安装到进阶技巧全面解析 Gin 的使用:快速入门示例(Hello Gin)、定义 RESTful 用户服务(增删改查接口实现),以及推荐实践如参数校验、中间件和路由分组等。通过对比标准库 `net/http`,Gin 提供更简洁灵活的开发体验。此外,还推荐了 GORM、Viper、Zap 等配合使用的工具库,助力高效开发。
|
数据可视化 图形学 UED
从模型托管到交互开发:DataV 如何简化三维 Web 应用构建?
从模型托管到交互开发:DataV 如何简化三维 Web 应用构建?
300 2
|
安全 Linux 开发工具
零基础构建开源项目OpenIM桌面应用和pc web- Electron篇
OpenIM 为开发者提供开源即时通讯 SDK,作为 Twilio、Sendbird 等云服务的替代方案。借助 OpenIM,开发者可以构建安全可靠的即时通讯应用,如 WeChat、Zoom、Slack 等。 本仓库基于开源版 OpenIM SDK 开发,提供了一款基于 Electron 的即时通讯应用。您可以使用此应用程序作为 OpenIM SDK 的参考实现。本项目同时引用了 @openim/electron-client-sdk 和 @openim/wasm-client-sdk,分别为 Electron 版本和 Web 版本的 SDK,可以同时构建 PC Web 程序和桌面应用(Wi
1101 2
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
542 0