You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core Web API:实现每3次调用返回不同状态码并追踪次数

ASP.NET Core Web API 按调用次数返回不同响应的实现方案

核心需求回顾

GET端点逻辑:

  • 第1、2次调用:返回状态码200及响应体 {"message": "OK"}
  • 第3、6、9...次调用:返回状态码503及空响应体

调用次数追踪的核心逻辑

要实现这个需求,关键是线程安全地统计调用次数——ASP.NET Core是多线程处理请求的,普通变量自增会出现并发计数错误。根据需求场景,分为两种常见实现方式:


方式1:全局调用计数(整个应用共享次数)

适合统计所有客户端总调用次数的场景,用单例服务或静态变量+原子操作保证线程安全。

实现代码(静态变量+Interlocked)

[ApiController]
[Route("api/test")]
public class TestController : ControllerBase
{
    // 静态变量存储全局调用次数
    private static int _globalCallCount = 0;

    [HttpGet]
    public IActionResult Get()
    {
        // 用Interlocked.Increment保证原子递增,避免并发计数错误
        var currentCount = Interlocked.Increment(ref _globalCallCount);

        if (currentCount % 3 == 0)
        {
            // 每3次调用返回503空响应
            return StatusCode(StatusCodes.Status503ServiceUnavailable);
        }

        // 其他情况返回200和指定响应体
        return Ok(new { message = "OK" });
    }
}

实现代码(单例服务解耦版)

如果想遵循依赖注入的设计原则,可将计数逻辑封装为单例服务:

  1. 定义计数服务接口与实现
public interface IGlobalCallCounter
{
    int IncrementAndGetCurrent();
}

public class GlobalCallCounter : IGlobalCallCounter
{
    private int _count = 0;

    public int IncrementAndGetCurrent()
    {
        return Interlocked.Increment(ref _count);
    }
}
  1. 在Program.cs注册单例服务
builder.Services.AddSingleton<IGlobalCallCounter, GlobalCallCounter>();
  1. 控制器注入使用
[ApiController]
[Route("api/test")]
public class TestController : ControllerBase
{
    private readonly IGlobalCallCounter _callCounter;

    public TestController(IGlobalCallCounter callCounter)
    {
        _callCounter = callCounter;
    }

    [HttpGet]
    public IActionResult Get()
    {
        var currentCount = _callCounter.IncrementAndGetCurrent();

        if (currentCount % 3 == 0)
        {
            return StatusCode(StatusCodes.Status503ServiceUnavailable);
        }

        return Ok(new { message = "OK" });
    }
}

方式2:客户端级调用计数(按用户/IP单独统计)

如果需要针对每个客户端单独计数(比如限制单个用户的请求频率),可以用缓存关联客户端标识(IP、Cookie、JWT等)。

实现代码(基于IMemoryCache)

[ApiController]
[Route("api/test")]
public class TestController : ControllerBase
{
    private readonly IMemoryCache _cache;

    public TestController(IMemoryCache cache)
    {
        _cache = cache;
    }

    [HttpGet]
    public IActionResult Get()
    {
        // 用客户端IP作为缓存键(实际场景可替换为用户ID、Cookie等更准确的标识)
        var clientKey = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown-client";
        
        // 从缓存获取当前计数,不存在则初始化为0
        var currentCount = _cache.GetOrCreate(clientKey, entry =>
        {
            // 设置缓存过期时间,比如1小时,根据需求调整
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
            return 0;
        });

        // 加锁保证缓存修改的线程安全
        lock (_cache)
        {
            currentCount++;
            _cache.Set(clientKey, currentCount);
        }

        if (currentCount % 3 == 0)
        {
            return StatusCode(StatusCodes.Status503ServiceUnavailable);
        }

        return Ok(new { message = "OK" });
    }
}

关键注意事项

  • 线程安全:必须用Interlocked或锁操作处理计数的修改,否则多请求并发时会出现计数错误。
  • 持久化需求:如果需要重启应用后保留计数,要将计数存储到数据库、Redis等持久化存储中,而不是内存变量。
  • 客户端标识准确性:按客户端计数时,IP可能存在NAT场景下的共享问题,推荐用用户登录后的ID或加密Cookie作为标识。

内容的提问来源于stack exchange,提问作者S Rallapalli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:29:54