ASP.NET Core自定义加密中间件触发客户端响应提前结束异常排查
问题根因与修复方案
核心问题点
- 未更新
Content-Length响应头:控制器返回原始响应内容时,框架会自动写入和原始内容长度匹配的Content-Length头。你将内容加密后长度发生了变化,但代码中没有同步修改该响应头,客户端按照原始长度读取响应数据,和实际返回的加密内容长度不匹配,就会触发「响应提前结束」的异常。application/json场景下Postman对响应格式校验更严格,所以直接无法展示内容,text/plain校验宽松所以能展示内容,但客户端依然会报错。 - StreamReader未配置
leaveOpen参数:默认情况下StreamReader销毁时会自动关闭底层的MemoryStream,属于不规范的流操作,可能引发不可预期的流异常。 - 缺少异常/非成功响应过滤逻辑:如果控制器返回重定向、错误状态码、或已经开始写入响应的场景,你依然强行修改响应内容,也会引发异常。
修复后的代码
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { string reponseContent = string.Empty; // 响应已经开始发送时不能再修改,直接跳过 if (context.Response.HasStarted) { await next(context); return; } var existingBody = context.Response.Body; using (var newBody = new MemoryStream()) { context.Response.Body = newBody; await next(context); // 只处理200状态码的响应,其他状态直接返回原始内容,可按需调整过滤条件 if (context.Response.StatusCode != StatusCodes.Status200OK) { newBody.Seek(0, SeekOrigin.Begin); await newBody.CopyToAsync(existingBody); context.Response.Body = existingBody; return; } context.Response.Body = existingBody; newBody.Seek(0, SeekOrigin.Begin); // 配置leaveOpen: true,避免StreamReader销毁时关闭底层MemoryStream using (var contentReader = new StreamReader(newBody, leaveOpen: true)) { reponseContent = await contentReader.ReadToEndAsync(); } string encryptedData = _cryptoService.Encrypt(reponseContent); // 同步更新Content-Length为加密后内容的实际长度 context.Response.ContentLength = Encoding.UTF8.GetByteCount(encryptedData); await context.Response.WriteAsync(encryptedData); } }
额外注意点
如果加密后的结果不是纯文本格式,可以根据实际业务需求同步调整Content-Type响应头。
内容的提问来源于stack exchange,提问作者Tony Riddle
相关产品推荐
相关产品推荐

