c# - 将标头请求和标头响应添加到 serilog 中间件日志记录
问题描述
我将 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方法的标头请求/响应的正确方法是什么,最好是通过中间件?
解决方案
我相信您知道要记录的标题键,对吗?
如果是这样,您可以使用:
.TryGetValue(TKey key, out TValue value)
- 如果请求具有这样的标头,则返回 true,并将值设置为 out 变量。下面的例子:
bool headerExists = httpContext.Request.Headers.TryGetValue("header-key", out var headerValue);
.this[string key]
- 如果字典有键,这将获取标题值。但是,如果密钥不存在,它会引发异常。下面的例子:
var headerValue = HttpContext.Request.Headers["header-key"];
另一方面,如果您有一个不想记录的标题列表,那么我认为您必须获取所有标题并排除这些标题。
推荐阅读
- objective-c - 当 Objc-C 桥接到 Swift 时如何查看方法签名,反之亦然?
- python - 将日期时间转换为纪元时出错,增加 5 秒,然后转换回日期时间
- corda - 如何解决单元测试“LinearState”的普通实现时抛出的“NotSerializableException”
- c# - 是否可以制作一个采用 Dictionary 的方法
>? - r - 实施严格的重载方法签名以防止误用
- reactjs - 从 Redux 迁移到 React Context API + hooks 时如何处理副作用
- jquery - 在数据表列复选框下拉列表中使用可选择的 jQuery
- json - 将一组表单输入转换为 JSON
- excel - VBA ExportAsFixedFormat to PDF 不打印某些图像
- css - 最佳实践:在背景上绘制形状