我有一个Asp.Net.Core应用程序,其中必须有一些日志记录,今天我尝试添加异常处理中间件。我用过UseExceptionHandler
它来自asp.net Diagonstics
.问题是当我的日志记录中间件在ExceptionHandler
中间件之后时
app.UseExceptionHandler("/error");
app.UseSerilogMiddleware();
当出现一些异常时,它不会将我重定向到我的自定义错误页面。
public async Task Invoke(HttpContext httpContext)
{
if (httpContext == null)
{
Log.Write(LogEventLevel.Fatal, "No HTTP context found!");
}
HttpRequest request = httpContext.Request;
var logger = GetExtendedLogger(request);
var stopwatchStart = Stopwatch.GetTimestamp();
try
{
var originalResponseBody = httpContext.Response.Body;
using (MemoryStream stream = new MemoryStream())
{
**httpContext.Response.Body = stream;**
await _next(httpContext);
stream.Seek(0, SeekOrigin.Begin);
var responseBody = new StreamReader(stream).ReadToEnd();
var elapsedMs = GetElapsedMilliseconds(stopwatchStart, Stopwatch.GetTimestamp());
var statusCode = httpContext.Response?.StatusCode;
var level = GetLogEventLevel(statusCode);
var log = Log
.ForContext("RequestHeaders", httpContext.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), destructureObjects: true)
.ForContext("RequestHost", httpContext.Request.Host)
.ForContext("RequestProtocol", httpContext.Request.Protocol);
logger.Write(level, MessageTemplate, httpContext.Request.Method, httpContext.Request.Path, statusCode, elapsedMs, responseBody);
stream.Seek(0, SeekOrigin.Begin);
await stream.CopyToAsync(originalResponseBody);
}
}
// Never caught, because LogException() returns false.
catch (Exception ex) when (AddExceptionLogEntry(logger, httpContext, GetElapsedMilliseconds(stopwatchStart, Stopwatch.GetTimestamp()), ex))
{
}
}'
这是日志记录中间件的一部分,但是我发现了导致问题的原因,但我没有解释。问题出在这一行httpContext.Response.Body = stream;
当我删除将响应正文设置为流时,一切正常。
附言日志记录方法从此处复制粘贴
TL;DR:在UseExceptionHandler
之前不要写入流,否则错误中间件无法写入重定向标头。
stream.Seek(0, SeekOrigin.Begin);
await stream.CopyToAsync(originalResponseBody);
在调用异常中间件之前,您正在写入响应流,因此重定向不起作用。HTTP 中的重定向是一种响应,它返回 http 代码 301 或 302,带有带有新 url 的 Location: http://example.com
标头。
但是,当您写入流时,标头已刷新,无法再更改。