You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 line
6.3KB

  1. using HealthMonitor.Common;
  2. using HealthMonitor.WebApi.Controllers.Api;
  3. using Microsoft.AspNetCore.Http;
  4. using Microsoft.Extensions.Logging;
  5. using Newtonsoft.Json;
  6. using System.IO;
  7. using System.Net;
  8. using System.Runtime.Serialization.Formatters.Binary;
  9. using System.Text;
  10. namespace HealthMonitor.WebApi.Middleware
  11. {
  12. public class LoggingMiddleware
  13. {
  14. private readonly RequestDelegate _next;
  15. private readonly ILogger<LoggingMiddleware> _logger;
  16. public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
  17. {
  18. _next = next;
  19. _logger = logger;
  20. }
  21. //public async Task InvokeAsync(HttpContext context)
  22. //{
  23. // //// 在请求处理之前记录日志
  24. // //using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = "" }))
  25. // using (new CustomizeStopWatch(nameof(LoggingMiddleware), _logger))
  26. // {
  27. // var request = await FormatRequest(context.Request);
  28. // _logger.LogInformation(request);
  29. // var originalBodyStream = context.Response.Body;
  30. // using var responseBody = new MemoryStream();
  31. // context.Response.Body = responseBody;
  32. // await _next(context);
  33. // var response = await FormatResponse(context.Response);
  34. // _logger.LogInformation(response);
  35. // await responseBody.CopyToAsync(originalBodyStream);
  36. // }
  37. //}
  38. public async Task InvokeAsync(HttpContext context)
  39. {
  40. //// 在请求处理之前记录日志
  41. //using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = "" }))
  42. using (new CustomizeStopWatch(nameof(LoggingMiddleware), _logger))
  43. {
  44. using var responseBody = new MemoryStream();
  45. var originalBodyStream = context.Response.Body;
  46. try
  47. {
  48. var request = await FormatRequest(context.Request);
  49. _logger.LogInformation(request);
  50. context.Response.Body = responseBody;
  51. await _next(context);
  52. }
  53. catch (Exception ex)
  54. {
  55. await HandleExceptionAsync(context, ex); // 捕获异常了 在HandleExceptionAsync中处理
  56. }
  57. var response = await FormatResponse(context.Response);
  58. _logger.LogInformation(response);
  59. await responseBody.CopyToAsync(originalBodyStream);
  60. }
  61. }
  62. private async Task<string> FormatRequest(HttpRequest request)
  63. {
  64. request.EnableBuffering();
  65. var body = await new StreamReader(request.Body).ReadToEndAsync();
  66. var formattedBody = FormatJson(body);
  67. request.Body.Position = 0;
  68. return $"请求: {request.Scheme} {request.Host}{request.Path} {request.QueryString} {formattedBody}";
  69. }
  70. private async Task<string> FormatResponse(HttpResponse response)
  71. {
  72. response.Body.Seek(0, SeekOrigin.Begin);
  73. var body = await new StreamReader(response.Body).ReadToEndAsync();
  74. var formattedBody = FormatJson(body);
  75. response.Body.Seek(0, SeekOrigin.Begin);
  76. return $"响应: {response.StatusCode}: {formattedBody}";
  77. }
  78. private static string FormatJson(string json)
  79. {
  80. if (string.IsNullOrEmpty(json))
  81. {
  82. return string.Empty;
  83. }
  84. try
  85. {
  86. var obj = JsonConvert.DeserializeObject(json);
  87. // return JsonConvert.SerializeObject(obj, Formatting.Indented);
  88. return JsonConvert.SerializeObject(obj);
  89. }
  90. catch
  91. {
  92. return json;
  93. }
  94. }
  95. private async Task HandleExceptionAsync(HttpContext context, Exception exception)
  96. {
  97. context.Response.ContentType = "application/json"; // 返回json 类型
  98. var response = context.Response;
  99. var errorResponse = new ErrorResponse
  100. {
  101. Success = false
  102. }; // 自定义的异常错误信息类型
  103. switch (exception)
  104. {
  105. case ApplicationException ex:
  106. if (ex.Message.Contains("Invalid token"))
  107. {
  108. response.StatusCode = (int)HttpStatusCode.Forbidden;
  109. errorResponse.Message = ex.Message;
  110. break;
  111. }
  112. response.StatusCode = (int)HttpStatusCode.BadRequest;
  113. errorResponse.Message = ex.Message;
  114. break;
  115. case KeyNotFoundException ex:
  116. response.StatusCode = (int)HttpStatusCode.NotFound;
  117. errorResponse.Message = ex.Message;
  118. break;
  119. default:
  120. response.StatusCode = (int)HttpStatusCode.InternalServerError;
  121. errorResponse.Message = "Internal Server errors. Check Logs!";
  122. break;
  123. }
  124. //_logger.LogError(exception.Message);
  125. //var result =JsonConvert.SerializeObject(ApiResponse<object>.Fail(response.StatusCode, $"{exception.Message}"));
  126. //await context.Response.WriteAsync(JsonConvert.SerializeObject(result));
  127. // Create the error response using ApiResponse.Fail
  128. var apiResponse = ApiResponse<object>.Fail(response.StatusCode, $"{exception.Message}\n{exception.InnerException}\n{exception.StackTrace}");
  129. // Convert the ApiResponse to JSON string
  130. var resultJson = JsonConvert.SerializeObject(apiResponse);
  131. // Convert the JSON string to bytes using UTF-8 encoding
  132. var resultBytes = Encoding.UTF8.GetBytes(resultJson);
  133. await response.Body.WriteAsync(resultBytes, 0, resultBytes.Length);
  134. var responseStr = await FormatResponse(context.Response);
  135. _logger.LogError(responseStr);
  136. }
  137. internal class ErrorResponse
  138. {
  139. public bool Success { get; set; }
  140. public string Message { get; set; } = String.Empty;
  141. }
  142. }
  143. }