咨询:ASP.NET Core中间件修改响应头报错,提示响应已启动头只读
解决ASP.NET Core中间件修改响应头时的"Headers are read-only"错误
这个错误的核心原因是:当你在await _next(context)之后修改响应头时,控制器已经完成处理并开始向客户端发送响应。HTTP协议要求响应头必须在响应体之前发送,此时响应头已经被提交,无法再修改。
下面是两种可行的解决办法:
方案一:使用OnStarting回调(仅修改响应头推荐)
利用HttpContext.Response.OnStarting注册回调,这个回调会在响应即将开始发送、响应头还可修改的时机执行,不需要缓存响应内容,性能更高。修改后的中间件代码:
public class EditResponseMiddleware { private readonly RequestDelegate _next; public EditResponseMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { // 在执行后续逻辑前,注册响应开始前的回调 context.Response.OnStarting(() => { context.Response.Headers["MyHeader"] = "Test"; return Task.CompletedTask; }); await _next(context); } }
方案二:替换响应流缓存内容(需修改响应体时使用)
如果需要在控制器执行完成后,根据响应内容动态修改响应头,或者同时修改响应体,可以通过替换响应流,将响应内容缓存到内存中,修改头后再将内容发送给客户端:
public class EditResponseMiddleware { private readonly RequestDelegate _next; public EditResponseMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { var originalResponseBody = context.Response.Body; using var responseBody = new MemoryStream(); context.Response.Body = responseBody; try { await _next(context); // 此时响应内容已存入内存流,可安全修改响应头 context.Response.Headers["MyHeader"] = "Test"; // 将缓存的响应内容写回原始流 responseBody.Seek(0, SeekOrigin.Begin); await responseBody.CopyToAsync(originalResponseBody); } finally { context.Response.Body = originalResponseBody; } } }
注意:方案二会将整个响应内容缓存到内存,处理大体积响应时需要注意内存占用问题。
内容的提问来源于stack exchange,提问作者Q-bertsuit
相关产品推荐
相关产品推荐

