Skip to main content

8 ASP.NET Core

缓存

客户端响应缓存

使用 cache-control 响应报文头, 实现客户端缓存这一请求的结果一段时间, cache-control: max-age=20 表示在浏览器中缓存 20 秒

// 设置缓存 20 秒
[ResponseCache(Duration = 20)]
[HttpGet}
public int GetNum()
{
    return 10;
}

服务器端响应缓存

app.UseCors();

// 启用服务器端响应缓存
app.UseResponseCaching();

app.MapControllers();

当使用"禁用缓存"时, 浏览器端请求时带有请求头 cache-control: no-cache, 即使启用了服务器端响应缓存, 服务器也不会从缓存中获取数据

服务器端响应缓存的问题

  • 无法解决恶意请求给服务器带来的压力
  • 响应状态码为 200 的 GET 或 HEAD 响应才可能被缓存, 报文头中不能含有 Authorization, Set-Cookie 等

内存缓存

// Program.cs
builder.Services.AddMemoryCache();

// 服务类
private readonly IMemoryCache _memoryCache;

public WeatherForecastController(IMemoryCache memoryCache)
{
    _memoryCache = memoryCache;
}

public async Task<ActionResult<Book>> GetBook(int id)
{
    // 从缓存取数据, 如果没有缓存, 则调用方法, 并返回数据(同时保存到缓存)
    var book = await _memoryCache.GetOrCreateAsync("Book_" + id, async entry =>
    {
        // 没有缓存, 查询数据
        Console.WriteLine($"没有缓存, 查询数据");
        var bookData = id switch
        {
            1 => new Book(1, "1"),
            2 => new Book(2, "2"),
            3 => new Book(3, "3"),
            _ => new Book(4, "4")
        };

        return bookData;
    });
  
    if (book == null)
    {
        return NotFound("查询不到数据");
    }

    return book;
}

缓存过期时间策略

绝对过期策略

var book = await _memoryCache.GetOrCreateAsync("Book_" + id, async entry =>
{
    var bookData = id switch
    {
        1 => new Book(1, "1"),
        2 => new Book(2, "2"),
        3 => new Book(3, "3"),
        _ => null
    };
    
    // 缓存时间为 1 分钟
    entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);

    return bookData;
});

滑动过期策略

// 从缓存取数据, 如果没有缓存, 则调用方法, 并返回数据(同时保存到缓存)
var book = await _memoryCache.GetOrCreateAsync("Book_" + id, async entry =>
{
    var bookData = id switch
    {
        1 => new Book(1, "1"),
        2 => new Book(2, "2"),
        3 => new Book(3, "3"),
        _ => null
    };

    // 在缓存没过期的时间, 请求一次的时候, 缓存有效期会自动延长
    entry.SlidingExpiration = TimeSpan.FromSeconds(10);

    return bookData;
});

同时设置两种策略

使用滑动过期时间策略, 如果一个缓存项一直被频繁访问, 那么这个缓存项就会一直被续期而不过期. 可以对一个缓存项同时设定滑动过期时间和绝对过期时间, 并且把绝对过期时间设定的比滑动过期时间长, 这样缓存项的内容会在绝对过期时间内随着访问被滑动续期, 但是一旦超过了绝对过期时间, 缓存项就会被删除

缓存问题

缓存穿透

缓存穿透是由于"查询不到的数据用 null 表示" 导致的, 因此解决方法是, 将"查不到"也当成数据放入缓存, 使用 GetOrCreateAsync() 方法可以解决这种问题, 因为这个方法会把 null 也当成合法的缓存值

 

缓存雪崩

缓存项集中过期引起的缓存雪崩, 解决方法是在基础过期时间之上, 加入一个随机的过期时间

// 不使用 new Random(), 高频访问时可能造成随机数是一样的
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(Random.Shared.Next(10, 20));


配置系统

默认添加的配置提供者

ASP.NET Core 默认添加了常用的提供者, 按以下顺序:

  • 加载现有的 IConfiguration
  • 加载项目根目录下的 appsettings.json
  • 加载项目根目录下的 appsettings.{Environment}.json
    • 环境变量 ASPNETCORE_ENVIRONMENT 的值
      • Development(开发环境)
      • Staging(测试环境)
      • Production(生产环境)
    • 代码中读取当前环境
      • 在 Program.cs 中
        • app.Environment.EnvironmentName
        • app.Environment.IsDevelopment()
      • 在其它代码文件中
        • 注入 IWebHostEnvironment 即可
  • 当程序运行在开发环境下, 程序会加载"用户机密"配置
  • 加载环境变量中的配置
  • 加载命令行中的配置