C#极简Web API:是否需EnableBuffering?如何记录无效请求内容?
解决ASP.NET Core极简API中记录无效请求内容的问题
是否需要调用EnableBuffering()?
是必须的。默认情况下ASP.NET Core的请求体流只能读取一次,且POST这类带请求体的请求流默认不支持回溯。调用EnableBuffering()会将请求体缓存到内存或磁盘,允许我们完整读取流内容,避免因流已被消费而无法获取请求体的问题。
中间件修改实现完整请求记录
以下是集成日志逻辑的修改方案(以内置ILogger为例):
首先,在构建应用时添加基础日志服务(极简场景下可直接用控制台日志):
var builder = WebApplication.CreateBuilder(args); // 添加控制台日志(可替换为Serilog等第三方日志库) builder.Logging.AddConsole(); var app = builder.Build(); // 原有静态文件、HSTS等配置代码保持不变
然后修改拦截无效请求的中间件:
app.Use(async (context, next) => { // 从请求服务容器中获取日志实例 var logger = context.RequestServices.GetRequiredService<ILogger<Program>>(); if (context.Request.Method.Equals("GET", StringComparison.InvariantCultureIgnoreCase) && !context.Request.Path.Value!.Contains(".")) { await next(); } else { context.Response.StatusCode = (int)HttpStatusCode.GatewayTimeout; // 启用请求体缓冲,允许多次读取流 context.Request.EnableBuffering(); // 收集请求头信息 var headerLog = string.Join(Environment.NewLine, context.Request.Headers.Select(h => $"{h.Key}: {string.Join(", ", h.Value)}")); // 收集请求体信息 string bodyLog = string.Empty; if (context.Request.Body.CanRead) { // 将流指针重置到起始位置 context.Request.Body.Position = 0; // leaveOpen: true 避免关闭流,保持规范 using var reader = new StreamReader(context.Request.Body, leaveOpen: true); bodyLog = await reader.ReadToEndAsync(); // 重置流指针,兼容后续可能的读取操作 context.Request.Body.Position = 0; } // 构造完整日志内容 var logMessage = $@" === 无效请求详情 === 请求方法: {context.Request.Method} 请求路径: {context.Request.Path} 查询字符串: {context.Request.QueryString} 请求头: {headerLog} 请求体: {bodyLog} ==================="; // 写入日志(可根据需求调整日志级别,如LogError) logger.LogWarning(logMessage); } });
关键注意事项
EnableBuffering()必须在读取请求体之前调用,否则会抛出流无法读取的异常。- 处理超大请求体时,可使用
EnableBuffering(int bufferThreshold)设置内存缓存阈值,超过阈值的内容会写入临时文件,避免内存溢出。 - 可根据需求过滤日志中的敏感信息,比如
Authorization请求头、请求体中的隐私数据。
内容的提问来源于stack exchange,提问作者Wim ten Brink
相关产品推荐
相关产品推荐

