ASP.NET Core日志中间件出现MemoryStream意外关闭异常如何解决
问题根因
CopyToAsync执行完成后,responseStream的指针已经移动到流的末尾,即使流未关闭直接读取也无法拿到内容- 默认的
StreamReader构造方法在实例被释放时,会自动关闭传入的底层流,你当前写法没有指定leaveOpen参数,读完内容后底层流被StreamReader主动关闭,这就是你报错的核心原因 - 不需要移除
MemoryStream的using语句,移除会导致内存无法及时释放,产生内存泄漏风险
修复方案
1. 修改中间件代码
在复制流到原始响应流之后,重新把responseStream的指针重置到起始位置,再调用日志方法:
public async Task InvokeAsync(HttpContext httpContext) { Stream originalResponseStream = httpContext.Response.Body; try { // log the response using (MemoryStream responseStream = new MemoryStream()) { httpContext.Response.Body = responseStream; await this.nextMiddleware.Invoke(httpContext); httpContext.Response.ContentLength = responseStream.Length; responseStream.Seek(0, SeekOrigin.Begin); await responseStream.CopyToAsync(originalResponseStream, 1024 * 16); // 新增:复制完成后重置流位置到开头,供日志读取 responseStream.Seek(0, SeekOrigin.Begin); Logger.LogHttpResponse(httpContext, session); } } finally { httpContext.Response.Body = originalResponseStream; } }
2. 修改日志读取方法
创建StreamReader时指定leaveOpen = true,避免StreamReader释放时关闭底层流,同时用using包裹StreamReader避免资源泄漏:
void LogHttpResponse(HttpContext context) { // 指定leaveOpen为true,StreamReader释放时不会关闭底层的Response.Body流 using var reader = new StreamReader(context.Response.Body, UTF8Encoding.UTF8, leaveOpen: true); var body = reader.ReadToEnd(); // log body }
额外注意事项
- 大文件/二进制响应不建议直接读取整个响应体,会占用大量内存,建议添加判断,仅读取文本类型的响应内容,同时限制最大读取长度,避免内存溢出
- 若响应是分块传输(
Transfer-Encoding: chunked),不要手动设置ContentLength,避免客户端接收异常
内容的提问来源于stack exchange,提问作者Mhd
相关产品推荐
相关产品推荐

