ASP.NET Core 7 源码阅读3:基础中间件
2023-06-11 23:26:04一、ExceptionHandler
ASP.NET Core管道最外面,就是app.UseExceptionHandler("/Home/Error");这个是全局异常处理,这个/Home/Error在哪里?
直接看源码
- UseExceptionHandler----ExceptionHandlerExtensions,开启新的Http管道,里面就是个ExceptionHandlerMiddlewareImpl------注册中间件
- 异常真的发生了,中间件的Invoke方法,看catch里面,最终是到ErrorPage.design.cs文件---请求响应时
- 没有Add,因为太简单了---没啥东西
中间件其实有3件事儿:
- AddXXX----builder.Build()期间,去完成的IOC注册
- UseXXXX---app.Run()期间,去完成中间件注册,组装Http管道
- Middleware的InvokeAsync()—请求响应时,才执行
关于全局异常处理中间件和Filter的区别
- ExceptionHandlerMiddleware是全局性质,是兜底的----而ExceptionFilter其实只管控制器-Action的异常,是管不了View-ResultFilter的异常
- 精细度不同,中间件只知道模糊信息,不适合做业务处理----ExceptionFilter贴近业务的,可以返回业务信息
- 其实完整的异常方案,就应该是二者叠加--
二、HTTPS
-
HstsMiddleware
HSTS 是 HTTP 严格传输安全(HTTP Strict Transport Security) 的缩写效果是:优先使用https---如果有https,就使用这个
源码解读: HstsMiddleware-----就是设置个header--- Strict-Transport-Security= maxage=
-
HttpsRedirection
UseHttpsRedirection 就是优先访问https,访问http会自动跳转(后台有配置https)效果:直接VS的https启动,访问http,开关中间件尝试https://localhost:7066 http://localhost:7067
源码:
- HttpsPolicyBuilderExtensions去注册下HttpsRedirectionMiddleware
- 没有Add
- 请求来了,会调用HttpsRedirectionMiddleware的Invoke方法
逻辑:如果是https--就继续--不是呢,就看看有没有配置https,然后返回个307+https地址,浏览器再次访问
三、StaticFiles
UseStaticFiles静态文件处理中间件---StaticFileHandler
- 静态文件是怎么响应的?自动读取的?任何文件的响应,都是由代码完成的----StaticFile中间件得在Routing之前
- 直接读源码,从StaticFileExtensions到StaticFileMiddleware,其核心逻辑:
- 各种检测---Get/Head—是否存在文件---类型是否支持
- 都通过就TryServeStaticFile----常规的就是200+SendFileAsync
- 不常规包括Header请求直接200-----缓存lastmodify请求,304和412---见后面缓存专题
StaticFiles管理
- 路径问题,默认是wwwroot,也可以修改
- 静态文件响应时, Header缓存处理---缓存; no-cache; no-store;
- 静态文件浏览DirectoryBrowser---学了这个+Startup,就是个大后门
防盗链
概念:就是防止外站盗用连接, www.a.com直接用 image.b.com的图, B不乐意
原理:图片是互联网公开的---处理图片请求时,做下urlreferer校验
实现:写个RefuseStealingMiddleWare,注册上去----请求来了,就是检测referer,合法,就继续默认流程;不合法,直接返回个指定图片
验证:done
- 可以通过ip去校验或者其他,随便写
- 浏览器是不会伪造referer,可以程序伪造referer,能避开,只能下载不能直接盗链
- 也可以用Nginx等服务器去配置完成
四、Session中间件
- Session是做啥的?用户持久化,保存在服务端的一段用户信息---以前是用的最多的,最常用的,直接内置在ASP.NET---ASP.NET Core没有内置,需要自己添加
- 全家桶设计与pay for what you use----其实现在用的更多的是Token
- Session的基础使用, Use+Add+读取使用
源码
从SessionMiddlewareExtensions到SessionMiddleware,直接看源码逻辑:
- 请求来了,走Invoke,基于Cookie检查,有没有SessionId
- 没有SessionId,则创建Guid的Sessionid,然后SetCookie写入响应
- 保存为context.Features.ISessionFeature,后面可以用
- 在finally里面把session重新存储下,就滑动过期了
Redis-Session
Session是存在服务器进程内存---1 重启丢失 2 不能共享集群下Session如何共享? SQLServer、第三方组件、 Redis
- 配置分布式存储,用Redis保存
- 启动Redis---启动多节点验证
builder.Services.AddDistributedRedisCache(options =>
{
options.Configuration = "127.0.0.1:6379";
options.InstanceName = "RedisDistributedCache123";
});
五、RateLimit
ASP.NET Core7.0新增的中间件,限流中间件,提供访问速率限制
-
理解限流?其实是为了程序的高可用---一个景区只能容纳5000人,真的放进来1w人那就毫无体验可言,上海迪士尼就有票售罄-----程序只能承载100QPS,如果来1000,大概率会挂----为了可用,限制请求
-
如何使用? Use + Add+ 标记
-
多策略:
-
应用场景: 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. 令牌桶策略
令牌桶算法是比较常见的限流算法之一
- 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理
- 根据限流大小,设置按照一定的速率往桶里添加令牌;
- 桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
- 请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
- 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;
4. 并发限制器
并发限制程序限制并发请求数。 每个请求都会将并发限制减少 1。请求完成后,限制将增加 1。
与限制指定时间段内请求总数的其他请求限制器不同,并发限制程序仅限制并发请求数,不限制一段时间内的请求数。
(等同于一个初始化固定数量的令牌桶)
https://learn.microsoft.com/zh-cn/aspnet/core/performance/ratelimit?preserve-view=true&view=aspnetcore-7.0#token
5. 源码阅读
这个源码不简单---但是也简单: 开源在AspNetCore
- 从RateLimiterServiceCollectionExtensions到简单IOC注册,做RateLimiterOptions配置,后面靠的是Policy---跟授权很像
- IOC注册里面有个RateLimiterOptionsExtensions,有各种Limiter注册
- RateLimiterApplicationBuilderExtensions是UseMiddleware,用的是RateLimitingMiddleware,里面完成请求检测