NetAdmin/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs
2023-12-08 10:41:08 +08:00

63 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}