mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-06-16 17:03:21 +08:00
63 lines
2.5 KiB
C#
63 lines
2.5 KiB
C#
using NetAdmin.Host.Utils;
|
||
|
||
namespace NetAdmin.Host.Middlewares;
|
||
|
||
/// <summary>
|
||
/// 请求审计中间件
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 放在所有中间件最前面
|
||
/// </remarks>
|
||
public sealed class RequestAuditMiddleware(
|
||
RequestDelegate next
|
||
, IOptions<DynamicApiControllerSettingsOptions> dynamicApiControllerSettingsOptions
|
||
, RequestLogger requestLogger)
|
||
{
|
||
private readonly PathString _defaultRoutePrefix
|
||
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}");
|
||
|
||
private readonly PathString _healthCheckRoutePrefix
|
||
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/health/check");
|
||
|
||
/// <summary>
|
||
/// 主函数
|
||
/// </summary>
|
||
public async Task InvokeAsync(HttpContext context)
|
||
{
|
||
// 跳过处理的情况:
|
||
if (!context.Request.Path.StartsWithSegments(_defaultRoutePrefix) // 非api请求
|
||
|| context.Request.Path.StartsWithSegments(_healthCheckRoutePrefix) // 健康检查
|
||
|| context.Request.Method == Chars.FLG_HTTP_METHOD_OPTIONS) { // is options 请求
|
||
await next(context).ConfigureAwait(false);
|
||
return;
|
||
}
|
||
|
||
// Response.Body流默认是不可读的,将Response.Body流替换成MemoryStream 使其可读
|
||
await using var ms = new MemoryStream();
|
||
var stream = context.Response.Body;
|
||
context.Response.Body = ms;
|
||
|
||
// 在控制台上输出分割线,区分不同请求
|
||
|
||
// 调用下一个中间件
|
||
var sw = Stopwatch.StartNew();
|
||
await next(context).ConfigureAwait(false);
|
||
sw.Stop();
|
||
|
||
_ = ms.Seek(0, SeekOrigin.Begin);
|
||
using var sr = new StreamReader(ms);
|
||
var responseBody = await sr.ReadToEndAsync().ConfigureAwait(false);
|
||
_ = ms.Seek(0, SeekOrigin.Begin);
|
||
await ms.CopyToAsync(stream).ConfigureAwait(false);
|
||
context.Response.Body = stream;
|
||
|
||
var exception = context.Features.Get<IExceptionHandlerFeature>();
|
||
var errorCode = context.Response.Headers[nameof(ErrorCodes)] //
|
||
.FirstOrDefault()
|
||
?.Enum<ErrorCodes>() ?? 0;
|
||
|
||
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMicroseconds, responseBody, errorCode
|
||
, exception)
|
||
.ConfigureAwait(false);
|
||
}
|
||
} |