Spiga

ASP.NET Core 7 源码阅读3:基础中间件

2023-06-11 23:26:04

一、ExceptionHandler

ASP.NET Core管道最外面,就是app.UseExceptionHandler("/Home/Error");这个是全局异常处理,这个/Home/Error在哪里?

直接看源码

  1. UseExceptionHandler----ExceptionHandlerExtensions,开启新的Http管道,里面就是个ExceptionHandlerMiddlewareImpl------注册中间件
  2. 异常真的发生了,中间件的Invoke方法,看catch里面,最终是到ErrorPage.design.cs文件---请求响应时
  3. 没有Add,因为太简单了---没啥东西

中间件其实有3件事儿:

  1. AddXXX----builder.Build()期间,去完成的IOC注册
  2. UseXXXX---app.Run()期间,去完成中间件注册,组装Http管道
  3. Middleware的InvokeAsync()—请求响应时,才执行

关于全局异常处理中间件和Filter的区别

  1. ExceptionHandlerMiddleware是全局性质,是兜底的----而ExceptionFilter其实只管控制器-Action的异常,是管不了View-ResultFilter的异常
  2. 精细度不同,中间件只知道模糊信息,不适合做业务处理----ExceptionFilter贴近业务的,可以返回业务信息
  3. 其实完整的异常方案,就应该是二者叠加--

二、HTTPS

  1. HstsMiddleware

    HSTS 是 HTTP 严格传输安全(HTTP Strict Transport Security) 的缩写效果是:优先使用https---如果有https,就使用这个

    源码解读: HstsMiddleware-----就是设置个header--- Strict-Transport-Security= maxage=

  2. HttpsRedirection

    UseHttpsRedirection 就是优先访问https,访问http会自动跳转(后台有配置https)效果:直接VS的https启动,访问http,开关中间件尝试https://localhost:7066 http://localhost:7067

    源码:

    1. HttpsPolicyBuilderExtensions去注册下HttpsRedirectionMiddleware
    2. 没有Add
    3. 请求来了,会调用HttpsRedirectionMiddleware的Invoke方法

    逻辑:如果是https--就继续--不是呢,就看看有没有配置https,然后返回个307+https地址,浏览器再次访问

三、StaticFiles

UseStaticFiles静态文件处理中间件---StaticFileHandler

  1. 静态文件是怎么响应的?自动读取的?任何文件的响应,都是由代码完成的----StaticFile中间件得在Routing之前
  2. 直接读源码,从StaticFileExtensions到StaticFileMiddleware,其核心逻辑:
    1. 各种检测---Get/Head—是否存在文件---类型是否支持
    2. 都通过就TryServeStaticFile----常规的就是200+SendFileAsync
    3. 不常规包括Header请求直接200-----缓存lastmodify请求,304和412---见后面缓存专题

StaticFiles管理

  1. 路径问题,默认是wwwroot,也可以修改
  2. 静态文件响应时, Header缓存处理---缓存; no-cache; no-store;
  3. 静态文件浏览DirectoryBrowser---学了这个+Startup,就是个大后门

防盗链

概念:就是防止外站盗用连接, www.a.com直接用 image.b.com的图, B不乐意

原理:图片是互联网公开的---处理图片请求时,做下urlreferer校验

实现:写个RefuseStealingMiddleWare,注册上去----请求来了,就是检测referer,合法,就继续默认流程;不合法,直接返回个指定图片

验证:done

  1. 可以通过ip去校验或者其他,随便写
  2. 浏览器是不会伪造referer,可以程序伪造referer,能避开,只能下载不能直接盗链
  3. 也可以用Nginx等服务器去配置完成

四、Session中间件

  1. Session是做啥的?用户持久化,保存在服务端的一段用户信息---以前是用的最多的,最常用的,直接内置在ASP.NET---ASP.NET Core没有内置,需要自己添加
  2. 全家桶设计与pay for what you use----其实现在用的更多的是Token
  3. Session的基础使用, Use+Add+读取使用

源码

从SessionMiddlewareExtensions到SessionMiddleware,直接看源码逻辑:

  1. 请求来了,走Invoke,基于Cookie检查,有没有SessionId
  2. 没有SessionId,则创建Guid的Sessionid,然后SetCookie写入响应
  3. 保存为context.Features.ISessionFeature,后面可以用
  4. 在finally里面把session重新存储下,就滑动过期了

Redis-Session

Session是存在服务器进程内存---1 重启丢失 2 不能共享集群下Session如何共享? SQLServer、第三方组件、 Redis

  1. 配置分布式存储,用Redis保存
  2. 启动Redis---启动多节点验证
builder.Services.AddDistributedRedisCache(options =>
{
    options.Configuration = "127.0.0.1:6379";
    options.InstanceName = "RedisDistributedCache123";
});

五、RateLimit

ASP.NET Core7.0新增的中间件,限流中间件,提供访问速率限制

  1. 理解限流?其实是为了程序的高可用---一个景区只能容纳5000人,真的放进来1w人那就毫无体验可言,上海迪士尼就有票售罄-----程序只能承载100QPS,如果来1000,大概率会挂----为了可用,限制请求

  2. 如何使用? Use + Add+ 标记

  3. 多策略:

  4. 应用场景: WebAPI可能需要限制下—来不及调优,就简单粗暴

    https://learn.microsoft.com/zh-cn/aspnet/core/performance/ratelimit?preserve-view=true&view=aspnetcore-7.0#tokenhttps://jerryluo.com/2022/05/27/RateLimiter/)

1. 固定窗口策略

固定窗口策略,最简单也是最容易实现的一种算法,但最有问题

从第一个请求开始计时,在一个时间段内(窗口)请求数不能超过100 00:00:01~00:01:00---最多只能100请求,更多就排队,甚至放弃00:01:01~00:02:00---排队的执行,接收新请求,加起来不超过100

缺陷:可能在临界点,集中遭遇请求,出现风险

2. 滑动窗口策略

滑动窗口策略,是改进了固定窗口策略:加权计数添加到当前窗口中的计数来计算估计数,如果估计数超过计数限制,则请求将被阻止。

估计数 = 前一窗口计数 * (1 - 当前窗口经过时间 / 单位时间) + 当前窗口计数避免请求集中添加,会分散一点

3. 令牌桶策略

令牌桶算法是比较常见的限流算法之一

  1. 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理
  2. 根据限流大小,设置按照一定的速率往桶里添加令牌;
  3. 桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
  4. 请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
  5. 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;

4. 并发限制器

并发限制程序限制并发请求数。 每个请求都会将并发限制减少 1。请求完成后,限制将增加 1。

与限制指定时间段内请求总数的其他请求限制器不同,并发限制程序仅限制并发请求数,不限制一段时间内的请求数。

(等同于一个初始化固定数量的令牌桶)

https://learn.microsoft.com/zh-cn/aspnet/core/performance/ratelimit?preserve-view=true&view=aspnetcore-7.0#token

5. 源码阅读

这个源码不简单---但是也简单: 开源在AspNetCore

  1. 从RateLimiterServiceCollectionExtensions到简单IOC注册,做RateLimiterOptions配置,后面靠的是Policy---跟授权很像
  2. IOC注册里面有个RateLimiterOptionsExtensions,有各种Limiter注册
  3. RateLimiterApplicationBuilderExtensions是UseMiddleware,用的是RateLimitingMiddleware,里面完成请求检测