WebAPI限流外部HttpClient调用 实现多请求复用单个外部请求结果
单Endpoint防缓存击穿调用方案
核心思路
你遇到的是典型的缓存击穿问题:热点缓存失效瞬间大量请求直接打到下游接口。我们可以通过在内存缓存中存储未完成的调用Task而非最终结果,实现同批次请求仅发起一次外部调用,其余请求复用同一结果的效果,不需要修改全局HttpClient配置,仅作用于目标endpoint。
实现代码示例
基于ASP.NET Core IMemoryCache的实现代码如下:
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using System.Net; [ApiController] [Route("api/[controller]")] public class ExternalDataController : ControllerBase { private readonly IMemoryCache _memoryCache; // 沿用你现有的静态HttpClient实例 private static readonly HttpClient _httpClient = new HttpClient(); // 缓存相关常量配置 private const string _externalApiCacheKey = "External:TargetApi:Result"; // 正常缓存有效期 private const int _normalCacheExpirationMinutes = 10; // 待完成Task的兜底超时时间,避免外部接口完全不可用时缓存卡死 private const int _pendingTaskTimeoutMinutes = 1; public ExternalDataController(IMemoryCache memoryCache) { _memoryCache = memoryCache; } [HttpGet("query")] public async Task<IActionResult> QueryExternalApi() { // 尝试从缓存获取调用Task var queryTask = _memoryCache.Get<Task<string>>(_externalApiCacheKey); if (queryTask == null) { // 无缓存时创建调用Task,先不await queryTask = _httpClient.GetStringAsync("https://你的外部接口地址"); // 先将未完成的Task写入缓存,加短超时兜底 _memoryCache.Set(_externalApiCacheKey, queryTask, TimeSpan.FromMinutes(_pendingTaskTimeoutMinutes)); try { // 等待调用完成 var result = await queryTask; // 调用成功后更新缓存为已完成的Task,设置正常有效期 _memoryCache.Set(_externalApiCacheKey, Task.FromResult(result), TimeSpan.FromMinutes(_normalCacheExpirationMinutes)); return Ok(result); } catch (HttpRequestException ex) { // 调用失败时移除缓存中的失败Task,允许后续请求重试 _memoryCache.Remove(_externalApiCacheKey); // 可根据需要添加降级逻辑,比如返回历史缓存值 return StatusCode((int)HttpStatusCode.ServiceUnavailable, "外部接口暂时不可用"); } } // 已有缓存(不管是待完成还是已完成的Task),直接等待结果返回 var data = await queryTask; return Ok(data); } }
方案优势
- 仅对当前Endpoint生效,不影响项目内其他接口的调用逻辑
- 和现有静态HttpClient的用法完全兼容,不需要修改全局HttpClient配置
- 同一时间最多只会发起一次外部接口调用,完全避免缓存击穿导致的下游接口压力放大问题
- 异常兜底逻辑完善,单次调用失败不会导致后续请求持续报错
扩展说明
如果你的服务是多实例部署,需要跨实例限制调用次数,可以在上述逻辑基础上加上分布式锁,限制全局仅一个实例发起外部调用,其余实例等待缓存写入后读取即可。
内容的提问来源于stack exchange,提问作者citronas
相关产品推荐
相关产品推荐

