【发布时间】:2021-04-29 12:10:23
【问题描述】:
我将 serilog 日志记录添加到我的 .net 核心 Web api,但我想扩展我当前的中间件以显示标头请求。 这是我的中间件类:
internal class SerilogRequestLoggerMiddleware
{
readonly RequestDelegate _next;
public SerilogRequestLoggerMiddleware(RequestDelegate next)
{
if (next == null) throw new ArgumentNullException(nameof(next));
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
// Push the user name into the log context so that it is included in all log entries
LogContext.PushProperty("UserName", httpContext.User.Identity.Name);
// Getting the request body is a little tricky because it's a stream
// So, we need to read the stream and then rewind it back to the beginning
string requestBody = "";
HttpRequestRewindExtensions.EnableBuffering(httpContext.Request);
Stream body = httpContext.Request.Body;
byte[] buffer = new byte[Convert.ToInt32(httpContext.Request.ContentLength)];
await httpContext.Request.Body.ReadAsync(buffer, 0, buffer.Length);
requestBody = Encoding.UTF8.GetString(buffer);
body.Seek(0, SeekOrigin.Begin);
httpContext.Request.Body = body;
Log.ForContext("RequestHeaders", httpContext.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), destructureObjects: true)
.ForContext("RequestBody", requestBody)
.Debug("Request information {RequestMethod} {RequestPath} information", httpContext.Request.Method, httpContext.Request.Path);
Log.Information(string.Format("Request Header: {0} ", requestBody));
Log.Information(string.Format("Request Body: {0} ", requestBody));
// The reponse body is also a stream so we need to:
// - hold a reference to the original response body stream
// - re-point the response body to a new memory stream
// - read the response body after the request is handled into our memory stream
// - copy the response in the memory stream out to the original response stream
using (var responseBodyMemoryStream = new MemoryStream())
{
var originalResponseBodyReference = httpContext.Response.Body;
httpContext.Response.Body = responseBodyMemoryStream;
//await _next(httpContext);
try
{
await _next(httpContext);
}
catch (Exception exception)
{
Guid errorId = Guid.NewGuid();
Log.ForContext("Type", "Error")
.ForContext("Exception", exception, destructureObjects: true)
.Error(exception, exception.Message + ". {@errorId}", errorId);
var result = JsonConvert.SerializeObject(new { error = exception.Message, errorId = errorId });
httpContext.Response.ContentType = "application/json";
httpContext.Response.StatusCode = 500;
await httpContext.Response.WriteAsync(result);
}
httpContext.Response.Body.Seek(0, SeekOrigin.Begin);
var responseBody = await new StreamReader(httpContext.Response.Body).ReadToEndAsync();
httpContext.Response.Body.Seek(0, SeekOrigin.Begin);
Log.ForContext("RequestBody", requestBody)
.ForContext("ResponseBody", responseBody)
.Debug("Response information {RequestMethod} {RequestPath} {statusCode}", httpContext.Request.Method, httpContext.Request.Path, httpContext.Response.StatusCode);
await responseBodyMemoryStream.CopyToAsync(originalResponseBodyReference);
}
}
}
我试过这样的
//byte[] bufferHeader = new byte[Convert.ToInt32(httpContext.Request.Headers.ContentLength)];
var header1 = httpContext.Request.Headers;
var bn = header1 .Values.ToList();
我得到了大约 20 个不同的对象,这些对象在我的初始 api 调用中没有出现(cors、localhost 地址、gz、我不熟悉的东西……)
有人可以在这里提出建议吗,记录 api 方法的标头请求/响应的正确方法是什么,最好是通过中间件?
【问题讨论】:
-
如果您不想记录所有标头,只需过滤特定标头并记录它们。但是,如果您只记录所有标头,它不会真正受到伤害
-
你能给我一个答案吗?谢谢
标签: c# asp.net-core asp.net-core-webapi serilog