如何在.NET Core 2.2中获取响应Content-Length用于遥测采集
ASP.NET Core 2.2 获取响应Content-Length实现遥测的方案
ASP.NET Core 默认采用流式响应模式,没有主动开启响应缓冲的前提下,服务端不会预计算整个响应的总大小,也就不会自动生成Content-Length响应头,这是你在常规中间件、过滤器阶段拿到的该值始终为null的核心原因。
以下是两个不需要自行读取响应流计算长度的实现方案:
方案1:自定义首中间件读取缓冲后的Content-Length
在请求管道的最开头注册自定义中间件,先开启响应缓冲,等后续所有管道逻辑处理完成、响应完全写入缓冲区后,直接读取系统自动生成的Content-Length即可:
public class ContentLengthLogMiddleware { private readonly RequestDelegate _next; public ContentLengthLogMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { // 开启响应缓冲,响应会先写入内存缓冲区而非直接发送到客户端 context.Response.EnableBuffering(); // 执行后续所有管道逻辑 await _next(context); // 此时响应已完全生成,Content-Length已被自动填充 if (context.Response.ContentLength.HasValue) { long responseLength = context.Response.ContentLength.Value; // 此处写入日志或者上报Application Insights的逻辑 } } }
注意:该中间件必须在
Startup.Configure方法的最顶部注册,保证所有响应处理逻辑都在await _next(context)阶段执行完成。
方案2:扩展Application Insights遥测初始化器
如果你的核心需求是上报到Application Insights,可以直接实现ITelemetryInitializer,在平台收集请求遥测时自动追加Content-Length属性,无需单独维护中间件:
public class ResponseLengthTelemetryInitializer : ITelemetryInitializer { private readonly IHttpContextAccessor _contextAccessor; public ResponseLengthTelemetryInitializer(IHttpContextAccessor contextAccessor) { _contextAccessor = contextAccessor; } public void Initialize(ITelemetry telemetry) { if (telemetry is RequestTelemetry reqTelemetry && _contextAccessor.HttpContext != null) { var response = _contextAccessor.HttpContext.Response; if (response.ContentLength.HasValue) { reqTelemetry.Properties["ResponseContentLength"] = response.ContentLength.Value.ToString(); } } } }
在Startup.ConfigureServices中注册对应服务即可生效:
// 注册HttpContext访问器 services.AddHttpContextAccessor(); // 注册自定义遥测初始化器 services.AddSingleton<ITelemetryInitializer, ResponseLengthTelemetryInitializer>();
注意事项
- 以上两个方案都依赖响应缓冲能力,ASP.NET Core 2.2 默认对常规请求开启缓冲,如果你有自定义中间件提前调用了
DisableBuffering()方法,需要调整对应逻辑保证缓冲可用。 - 对于文件下载之类的大响应,缓冲会占用较多内存,如果你需要统计这类响应的长度,才需要考虑自定义响应流包装器统计写入字节数的方案。
内容的提问来源于stack exchange,提问作者Adent
相关产品推荐
相关产品推荐

