当前位置: 首页 > news >正文

ASP.NET Core 请求日志中间件

间件会记录请求方法、路径、查询字符串、请求体和运行时间,同时还会处理一些特定路由(如 SignalR 和 Swagger)的请求,避免记录这些请求。

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Serilog;namespace LogMiddleware
{public class LogMiddleware{private readonly RequestDelegate _next;public LogMiddleware(RequestDelegate next){_next = next;}public async Task Invoke(HttpContext context){// 处理特定路径if (context.Request.Path.HasValue &&(context.Request.Path.Value.IndexOf("SignalR", StringComparison.InvariantCultureIgnoreCase) > -1 ||context.Request.Path.Value.IndexOf("Swagger", StringComparison.InvariantCultureIgnoreCase) > -1)){await _next(context);return;}// 添加请求时间戳if (!context.Request.Headers.ContainsKey("REQST")){context.Request.Headers.Add("REQST", DateTime.Now.ToString());}context.Request.EnableBuffering(); // 允许多次读取请求体string requestBody = string.Empty;using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, leaveOpen: true)){requestBody = await reader.ReadToEndAsync();context.Request.Body.Position = 0; // 重置请求流的位置}// 创建一个新的 MemoryStream 用于捕获响应var originalBodyStream = context.Response.Body;using (var responseBody = new MemoryStream()){context.Response.Body = responseBody; // 使用新的 MemoryStream 代替响应流Stopwatch stopwatch = new Stopwatch();stopwatch.Start();try{await _next(context); // 调用下一个中间件// 记录响应数据context.Response.Body.Seek(0, SeekOrigin.Begin);var responseText = await new StreamReader(context.Response.Body).ReadToEndAsync();context.Response.Body.Seek(0, SeekOrigin.Begin); // 重置响应流的位置stopwatch.Stop();long runTime = stopwatch.ElapsedMilliseconds;WriteVisitLog(context, runTime, requestBody, responseText);}finally{// 将捕获的响应流写回原始响应流await responseBody.CopyToAsync(originalBodyStream);context.Response.Body = originalBodyStream; // 恢复原始响应流}}}private void WriteVisitLog(HttpContext context, long runTime, string requestBody, string responseBody){// 记录请求详细信息var requestInfo = new{Method = context.Request.Method,Path = context.Request.Path,QueryString = context.Request.QueryString.ToString(),Headers = context.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()),Body = requestBody,RunTime = runTime,ResponseBody = responseBody};var correlationId = requestInfo.Headers.ContainsKey("X-Correlation-Id") ? requestInfo.Headers["X-Correlation-Id"] : "N/A";var bodyOutput = string.IsNullOrWhiteSpace(requestInfo.Body) ? string.Empty : $"Body: {requestInfo.Body}; ";var queryStringOutput = string.IsNullOrWhiteSpace(requestInfo.QueryString) ? string.Empty : $"QueryString: {requestInfo.QueryString}; ";var responseOutput = string.IsNullOrWhiteSpace(requestInfo.ResponseBody) ? string.Empty : $"Response: {requestInfo.ResponseBody}; ";// 仅在 QueryString 和 Body 不为空时输出var logMessage = $"[{correlationId}] Request Info: Method: {requestInfo.Method}; Path: {requestInfo.Path}; " +$"{queryStringOutput}{bodyOutput}{responseOutput}Run Time: {requestInfo.RunTime} ms";// 仅当 logMessage 不包含空部分时才记录if (!string.IsNullOrWhiteSpace(queryStringOutput) || !string.IsNullOrWhiteSpace(bodyOutput) || !string.IsNullOrWhiteSpace(responseOutput)){Log.Information(logMessage);}}}
}
  1. 捕获响应数据

    • 在中间件中,使用 MemoryStream 替代 HttpContext.Response.Body 以捕获响应数据。
    • 在调用下一个中间件 (await _next(context);) 后,读取 responseBody 的内容。
  2. 记录响应数据

    • 在 WriteVisitLog 方法中,将响应数据作为 ResponseBody 记录。
    • 通过 string.IsNullOrWhiteSpace 检查响应数据是否为空,以决定是否输出相关信息。
  3. 恢复响应流

    • 在完成响应后,将捕获的 responseBody 内容写入到原始的 Response.Body 中,以确保响应能够正确返回给客户端。

使用:

 // 注册 LogMiddleware
 app.UseMiddleware<LogMiddleware>();

http://www.lryc.cn/news/578380.html

相关文章:

  • MediaPipe框架解析(三):android edge_detection详解
  • 深度学习中常见激活函数总结
  • k8s pod调度基础
  • spring-ai-alibaba 1.0.0.2 学习(五)——集成外部工具
  • 使用tensorflow的线性回归的例子(三)
  • 【C#】如果有一个数值如 168.0000100,如何去除末尾的无效零,只显示有效的小数位数,让DeepSeek给我们解答
  • C++11中 <cinttypes>的入门与精通
  • CppCon 2018 学习:A New Take on Polymorphism
  • Redis——常用指令汇总指南(一)
  • Electron 沙箱模式深度解析:构建更安全的桌面应用
  • 笨方法学python-习题12
  • jQuery 安装使用教程
  • 【算法】动态规划 斐波那契类型: 740. 删除并获得点数
  • 设计模式之上下文对象设计模式
  • IntelliJ IDEA 2025- 下载安装教程图文版详细教程(附激活码)
  • 使用nlohmann/json.hpp实现json文件读写
  • SpringBoot全局异常详解
  • 【实时Linux实战系列】实时数据库与数据存储方案
  • 学习threejs,使用自定义GLSL 着色器,生成艺术作品
  • 使用Rust原生实现小波卡尔曼滤波算法
  • 408第三季part1 - 操作系统 - 基本分页
  • 算法赋能管理:工厂安全与效率双突破
  • 【仿muduo库实现并发服务器】Channel模块
  • 回转体航行器控制系统中深度控制与俯仰姿态控制的解耦策略
  • 基于springboot的养老院管理系统
  • C# Linq to XML 详解:强大的XML处理工具
  • (自用)Java学习-5.21(支付宝沙箱支付、Vue总结)
  • 插入排序解析
  • sqlmap学习笔记ing(1.Easy_SQLi(时间,表单注入))
  • Django打造智能Web机器人控制平台