如何缓存API POST响应并基于请求Body参数而非GET参数做VaryBy区分
基于POST请求体字段实现响应缓存的方案
默认[ResponseCache]特性提供的VaryByQueryKeys仅支持对查询字符串参数做缓存区分,无法直接适配POST接口的请求体字段,你可以通过自定义缓存key计算规则实现需求,具体步骤如下:
步骤1:调整Action的ResponseCache配置
将VaryByCustom参数设置为自定义标识,示例代码如下:
[HttpPost] [ResponseCache(Duration = 600, Location = ResponseCacheLocation.Any, VaryByCustom = "ManufacturersRequest")] public ActionResult<IEnumerable<Manufacturer>> Manufacturers([FromBody] ManufacturersRequest manufacturersRequest) { // 你的业务逻辑 }
步骤2:配置全局响应缓存的自定义key规则
在Program.cs(.NET 6+)或Startup.cs的服务注册环节,添加响应缓存的自定义key计算逻辑:
builder.Services.AddResponseCaching(options => { options.OnComputeCacheKey = async context => { var request = context.HttpContext.Request; // 仅匹配目标POST接口,避免影响其他接口 if (request.Path.Equals("/你的接口路径/manufacturers", StringComparison.OrdinalIgnoreCase) && request.Method == HttpMethod.Post.Method) { // 启用请求体可重读,避免后续ModelBinding无法获取参数 request.EnableBuffering(); request.Body.Position = 0; // 读取请求体并反序列化 using var reader = new StreamReader(request.Body, leaveOpen: true); var bodyContent = await reader.ReadToEndAsync(); request.Body.Position = 0; var reqObj = System.Text.Json.JsonSerializer.Deserialize<ManufacturersRequest>(bodyContent); if (reqObj != null) { // 将需要区分缓存的字段拼接到缓存key中 context.CacheKey += $"|Category:{reqObj.Category}|manu_filter:{reqObj.manu_filter}|imagesize:{reqObj.imagesize}"; } } }; }); // 别忘了在中间件管道里加app.UseResponseCaching(),要放在app.MapControllers()之前
注意事项
- 如果你的接口需要兼容客户端/代理缓存,要确认端侧可以识别自定义的缓存规则,否则建议将
ResponseCache.Location改为ResponseCacheLocation.Server,仅在服务端做缓存避免错乱。 - 如果请求体体积较大,可以直接解析JSON字符串提取指定字段,无需完整反序列化,降低性能损耗。
- 如果你有更复杂的缓存规则需求,也可以选择手动引入分布式缓存(如IDistributedCache),自行拼接字段作为缓存key存储接口返回结果,灵活度更高。
内容的提问来源于stack exchange,提问作者user964787
相关产品推荐
相关产品推荐

