using HealthMonitor.Common; using HealthMonitor.WebApi.Controllers.Api; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System.IO; using System.Net; using System.Runtime.Serialization.Formatters.Binary; using System.Text; namespace HealthMonitor.WebApi.Middleware { public class LoggingMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public LoggingMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } //public async Task InvokeAsync(HttpContext context) //{ // //// 在请求处理之前记录日志 // //using (_logger.BeginScope(new Dictionary { ["RequestId"] = "" })) // using (new CustomizeStopWatch(nameof(LoggingMiddleware), _logger)) // { // var request = await FormatRequest(context.Request); // _logger.LogInformation(request); // var originalBodyStream = context.Response.Body; // using var responseBody = new MemoryStream(); // context.Response.Body = responseBody; // await _next(context); // var response = await FormatResponse(context.Response); // _logger.LogInformation(response); // await responseBody.CopyToAsync(originalBodyStream); // } //} public async Task InvokeAsync(HttpContext context) { //// 在请求处理之前记录日志 //using (_logger.BeginScope(new Dictionary { ["RequestId"] = "" })) using (new CustomizeStopWatch(nameof(LoggingMiddleware), _logger)) { using var responseBody = new MemoryStream(); var originalBodyStream = context.Response.Body; try { var request = await FormatRequest(context.Request); _logger.LogInformation(request); context.Response.Body = responseBody; await _next(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex); // 捕获异常了 在HandleExceptionAsync中处理 } var response = await FormatResponse(context.Response); _logger.LogInformation(response); await responseBody.CopyToAsync(originalBodyStream); } } private async Task FormatRequest(HttpRequest request) { request.EnableBuffering(); var body = await new StreamReader(request.Body).ReadToEndAsync(); var formattedBody = FormatJson(body); request.Body.Position = 0; return $"请求: {request.Scheme} {request.Host}{request.Path} {request.QueryString} {formattedBody}"; } private async Task FormatResponse(HttpResponse response) { response.Body.Seek(0, SeekOrigin.Begin); var body = await new StreamReader(response.Body).ReadToEndAsync(); var formattedBody = FormatJson(body); response.Body.Seek(0, SeekOrigin.Begin); return $"响应: {response.StatusCode}: {formattedBody}"; } private static string FormatJson(string json) { if (string.IsNullOrEmpty(json)) { return string.Empty; } try { var obj = JsonConvert.DeserializeObject(json); // return JsonConvert.SerializeObject(obj, Formatting.Indented); return JsonConvert.SerializeObject(obj); } catch { return json; } } private async Task HandleExceptionAsync(HttpContext context, Exception exception) { context.Response.ContentType = "application/json"; // 返回json 类型 var response = context.Response; var errorResponse = new ErrorResponse { Success = false }; // 自定义的异常错误信息类型 switch (exception) { case ApplicationException ex: if (ex.Message.Contains("Invalid token")) { response.StatusCode = (int)HttpStatusCode.Forbidden; errorResponse.Message = ex.Message; break; } response.StatusCode = (int)HttpStatusCode.BadRequest; errorResponse.Message = ex.Message; break; case KeyNotFoundException ex: response.StatusCode = (int)HttpStatusCode.NotFound; errorResponse.Message = ex.Message; break; default: response.StatusCode = (int)HttpStatusCode.InternalServerError; errorResponse.Message = "Internal Server errors. Check Logs!"; break; } //_logger.LogError(exception.Message); //var result =JsonConvert.SerializeObject(ApiResponse.Fail(response.StatusCode, $"{exception.Message}")); //await context.Response.WriteAsync(JsonConvert.SerializeObject(result)); // Create the error response using ApiResponse.Fail var apiResponse = ApiResponse.Fail(response.StatusCode, $"{exception.Message}\n{exception.InnerException}\n{exception.StackTrace}"); // Convert the ApiResponse to JSON string var resultJson = JsonConvert.SerializeObject(apiResponse); // Convert the JSON string to bytes using UTF-8 encoding var resultBytes = Encoding.UTF8.GetBytes(resultJson); await response.Body.WriteAsync(resultBytes, 0, resultBytes.Length); var responseStr = await FormatResponse(context.Response); _logger.LogError(responseStr); } internal class ErrorResponse { public bool Success { get; set; } public string Message { get; set; } = String.Empty; } } }