netcore api请求日志输出中间件
/// <summary>
/// 统一错误处理中间件
/// </summary>
public class CustomExceptionMiddleware
{
private readonly RequestDelegate _next;
public CustomExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var responseBodyStream = context.Response.Body;
try
{
await LogRequest(context.Request);
//Copy a pointer to the original response body stream
using (var ms = new MemoryStream())
{
context.Response.Body = ms;
await _next(context);
await LogResponse(context.Response, ms);
ms.Position = 0;
await ms.CopyToAsync(responseBodyStream);
}
}
catch (Exception ex)
{
LogHelper.Error("Error", ex);
await HandleExceptionAsync(context, responseBodyStream, ex).ConfigureAwait(true);
}
}
private async Task HandleExceptionAsync(HttpContext context, Stream body, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 200;// (int)HttpStatusCode.InternalServerError;
var data = new { code = 500, message = exception.Message };
var result = JsonHelper.ToJson(data);
using (var ms = new MemoryStream())
{
//ms.Seek(0, SeekOrigin.Begin);
await ms.WriteAsync(Encoding.UTF8.GetBytes(result));
ms.Seek(0, SeekOrigin.Begin);
await ms.CopyToAsync(body);
}
}
#region 日志
private async Task<string> FormatRequest(HttpRequest request)
{
var body = "";
if (request.ContentLength > 0)
{
if (!request.Body.CanSeek)
{
request.EnableBuffering();
await request.Body.DrainAsync(CancellationToken.None);
request.Body.Seek(0L, SeekOrigin.Begin);
}
var contentType = request.ContentType;
var mediaType = contentType == null ? default(MediaType) : new MediaType(contentType);
var encoding = mediaType.Encoding;
if (encoding == null)
{
encoding = Encoding.UTF8;
}
using (StreamReader sr = new StreamReader(request.Body, encoding, true, 1024, true))//这里注意Body部分不能随StreamReader一起释放
{
body = await sr.ReadToEndAsync();
request.Body.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化,否则后面的InputFormatter会无法读取
}
}
return body;
}
private async Task LogResponse(HttpResponse response, MemoryStream ms)
{
ms.Position = 0;
var body = await new StreamReader(ms).ReadToEndAsync();
response.Body.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化,否则后面的InputFormatter会无法读取
LogHelper.Info($"id:{Thread.GetCurrentProcessorId()};Code:{response.StatusCode};body:{body}");
}
/// <summary>
/// 请求日志
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private async Task LogRequest(HttpRequest request)
{
var method = request.Method;
var query = "";
if (request.Query.Count > 0)
{
query = request.QueryString.Value;
}
var form = new StringBuilder();
if (method.Equals("post", StringComparison.OrdinalIgnoreCase) && request.HasFormContentType)
{
foreach (var item in request.Form)
{
form.Append($"{item.Key}={item.Value}&");
}
}
var body = await FormatRequest(request);
LogHelper.Info($"id:{Thread.GetCurrentProcessorId()};api:{request.Host}{request.Path};method:{method};query:{query}; form:{form.ToString()}; body:{body}");
}
#endregion
}