ASP.NET Core ResponseCaching:基于 VaryByHeader 定制缓存 Key
ASP.NET Core ResponseCaching 提供了缓存http响应内容的能力,通过它可以在本地内存中直接缓存http响应内容,这是速度最快的服务端缓存,省却了网络传输与生成响应内容的开销,是 Memcached 或 Redis 等分布式缓存的有效补充。欲更多了解 ResponseCaching ,推荐阅读园子里的一篇博文 谈谈ASP.NET Core中的ResponseCaching 。
ResponseCaching 提供了 VaryByHeader 与 VaryByQueryKeys 这两种种方式配置缓存 Key ,我们在使用 VaryByHeader 时发现一个问题 —— 使用 VaryByHeader 时如果不做限制,会面临缓存被撑爆的风险。比如上面根据 Accept 请求头进行缓存,由于客户端可以任意修改请求头,如果有爬虫发出大量的请求,并且每个请求的 Accept 请求头不一样,ResponseCaching 会因此为每个请求生成缓存项,直至内存被耗尽。
为了避免这个问题,我们需要对基于请求头生成缓存 key 的规则进行限制,但 ResponseCaching 没有提供对应的定制能力。
我们开始想到的一个解决方法是基于适配器模式自己实现 IResponseCachingKeyProvider 接口,代码如下:
public class CustomResponseCachingKeyProvider : IResponseCachingKeyProvider
{
private static readonly char KeyDelimiter = '\x1e';
private ResponseCachingKeyProvider _responseCachingKeyProvider; public CustomResponseCachingKeyProvider(ResponseCachingKeyProvider responseCachingKeyProvider)
{
_responseCachingKeyProvider = responseCachingKeyProvider;
} public string CreateBaseKey(ResponseCachingContext context)
{
return _responseCachingKeyProvider.CreateBaseKey(context);
} public IEnumerable<string> CreateLookupVaryByKeys(ResponseCachingContext context)
{
return _responseCachingKeyProvider.CreateLookupVaryByKeys(context);
} public string CreateStorageVaryByKey(ResponseCachingContext context)
{
var key = _responseCachingKeyProvider.CreateStorageVaryByKey(context);
var accept = context.HttpContext.Request.GetTypedHeaders().Accept;
if (accept.Any(x => x.MediaType == "application/json"))
{
key += KeyDelimiter + "accept=application/json";
}
else
{
key += KeyDelimiter + "accept=text/plain";
} return key;
}
}
然后在 Startup 的 ConfigureServices 方法中进行注册
services.AddTransient<ResponseCachingKeyProvider>();
services.AddSingleton<IResponseCachingKeyProvider, CustomResponseCachingKeyProvider>();
services.AddResponseCaching();
除了上面这两步之外,还要给 VaryByHeader 随便赋个值,因为 CreateStorageVaryByKey() 方法只有在 VaryByHeader 或 VaryByQueryKeys 有值的情况下才会被调用。
[ResponseCache(Duration = , VaryByHeader = "_")]
实现后觉得这不是一个优雅的解决方法。
后来尝试修改 ResponseCaching 的源代码,但 ResponseCaching 在设计时并没有考虑到这个场景,修改工作量比较大。
再后来转念一想,不用这么麻烦,可以借助于已有的 VaryByHeader 机制,通过 middleware 根据客户端的请求头生成用于 VaryByHeader 的请求头,middleware 的代码如下
app.Use(async (context, next) =>
{
var accept = context.Request.GetTypedHeaders().Accept;
var mediaTypes = new string[] { "application/json", "text/html" };
var mediaType = accept.Select(x => x.MediaType).FirstOrDefault(x => mediaTypes.Contains(x.Value));
context.Request.Headers.Add("Accept-MediaType", mediaType == null ? "text/plain" : mediaType.Value);
await next.Invoke();
});
ResponseCaching 属性的声明如下
[ResponseCache(Duration = , VaryByHeader = "Accept-MediaType", VaryByQueryKeys = new string[] { "id" })]
折腾了 1 天的问题换了个思路 10 分钟搞定。
另外,使用 ResponseCaching 还需要注意一个地方,如果用到了 CORS ,还需要在 VaryByHeader 中添加 "Origin"
[ResponseCache(Duration = , VaryByHeader = "Accept-MediaType,Origin", VaryByQueryKeys = new string[] { "id" })]
ASP.NET Core ResponseCaching:基于 VaryByHeader 定制缓存 Key的更多相关文章
- ASP.NET Core 中间件之压缩、缓存
前言 今天给大家介绍一下在 ASP.NET Core 日常开发中用的比较多的两个中间件,它们都是出自于微软的 ASP.NET 团队,他们分别是 Microsoft.AspNetCore.Respons ...
- ASP.NET Core 使用 Redis 实现分布式缓存:Docker、IDistributedCache、StackExchangeRedis
ASP.NET Core 使用 Redis 实现分布式缓存:Docker.IDistributedCache.StackExchangeRedis 前提:一台 Linux 服务器.已安装 Docker ...
- ASP.NET Core WebApi基于JWT实现接口授权验证
一.ASP.Net Core WebApi JWT课程前言 我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再 ...
- ASP.NET Core WebApi基于Redis实现Token接口安全认证
一.课程介绍 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebSer ...
- asp.net core 自定义基于 HttpContext 的 Serilog Enricher
asp.net core 自定义基于 HttpContext 的 Serilog Enricher Intro 通过 HttpContext 我们可以拿到很多有用的信息,比如 Path/QuerySt ...
- Asp.Net Core 2.1+的视图缓存(响应缓存)
响应缓存Razor 页与 ASP.NET 核心 2.0 中不支持. 此功能将支持ASP.NET 核心 2.1 版本. 在老的版本的MVC里面,有一种可以缓存视图的特性(OutputCache),可以保 ...
- 详解Asp.Net Core 2.1+的视图缓存(响应缓存)
响应缓存Razor 页与 ASP.NET 核心 2.0 中不支持. 此功能将支持ASP.NET 核心 2.1 版本. 在老的版本的MVC里面,有一种可以缓存视图的特性(OutputCache),可以保 ...
- Asp.net Core, 基于 claims 实现权限验证 - 引导篇
什么是Claims? 这个直接阅读其他大神些的文章吧,解释得更好. 相关文章阅读: http://www.cnblogs.com/JustRun1983/p/4708176.html http://w ...
- (17)ASP.NET Core EF基于数据模型创建数据库
1.简介 使用Entity Framework Core构建执行基本数据访问的ASP.NET Core MVC应用程序.使用迁移(Migrations)基于数据模型创建数据库,你可以在Windows上 ...
随机推荐
- JSONObject、JSONArray、Map、JavaBean的相互转换
1,JSONObject json对象,就是一个键对应一个值,使用的是大括号{ },如:{key:value} 2,JSONArray json数组,使用中括号[ ],只不过数组里面的项也是json键 ...
- [转]tensorflow中的gather
原文链接 tensorflow中取下标的函数包括:tf.gather , tf.gather_nd 和 tf.batch_gather. 1.tf.gather(params,indices,vali ...
- Shell脚本编程(三):shell参数传递
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推…… 实例 以下实例我们向脚本传递三 ...
- invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
Mac系统升级git会找不到并且报错:xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) ...
- [AS3 3D Demo] Stage3D学习过程中开发的3个Demo
1.飞机大战 基于Starling开发,使用了对象池技术的Demo. 2.3D人物2D背景游戏Demo 基于Away3D开发,实现了3D资源管理.寻路和跳跃等功能. 3.全3D游戏Demo 基于Awa ...
- EPOLL AND Nonblocking I/O
https://medium.com/@copyconstruct/nonblocking-i-o-99948ad7c957 https://idndx.com/2014/09/02/the-impl ...
- crawler_exa1
编辑中... #! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma ''' 网页爬虫,版本 2017-09-20 21:16 ' ...
- Word Embedding/RNN/LSTM
Word Embedding Word Embedding是一种词的向量表示,比如,对于这样的"A B A C B F G"的一个序列,也许我们最后能得到:A对应的向量为[0.1 ...
- 【Leetcode】收集
万事总要有个开头,来吧. 问题原题看情况,如果我能用中文准确地表述出来的话那就用中文说一下.也有可能完全不说… ■ twoSum 问题: 参数是一个数组nums和一个目标数target,寻找nums中 ...
- DirectX using C++_error X3539:ps1_x is no longer supported...解决方案
问题来源 在研究HLSL时编译一个demo出现了error X3539的问题 解决方案 将代码中的ps_1_1 改为ps_2_0 PixelShader = compile ps_1_1 PS(); ...