using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using WIDESEA_Core.Helper; using WIDESEA_Core.LogHelper; namespace WIDESEA_Core.Middlewares { /// /// 记录请求和响应数据 /// public class ApiLogMiddleware { /// /// /// private readonly RequestDelegate _next; public ApiLogMiddleware(RequestDelegate next, ILogger logger) { _next = next; } //todo /// /// API日志中间件,用于处理HTTP请求和响应的日志记录 /// /// /// 1. 检查系统过期时间,若过期则返回500错误 /// 2. 仅处理包含"api"路径的请求 /// 3. 记录请求和响应数据到日志系统 /// 4. 支持通过配置忽略特定URL的日志记录 /// /// 当前HTTP上下文 /// 异步任务 public async Task InvokeAsync(HttpContext context) { if (App.ExpDateTime != null && (DateTime.Now - App.ExpDateTime.GetValueOrDefault()).TotalSeconds > 0) { context.Response.StatusCode = HttpStatusCode.InternalServerError.ObjToInt(); context.Response.ContentType = "application/json"; var json = new WebResponseContent(); json.Message = HttpStatusCode.InternalServerError.ToString();//错误信息 json.Code = 500;//500异常 StreamWriter streamWriter = new StreamWriter(context.Response.Body); await streamWriter.WriteAsync(json.Serialize()); return; } // 过滤,只有接口 if (context.Request.Path.Value?.Contains("api") ?? false) { context.Request.EnableBuffering(); Stream originalBody = context.Response.Body; string requestParam = string.Empty; string responseParam = string.Empty; try { string? apiIgnore = AppSettings.GetValue("ApiLogIgnore")?.ToString(); string[] ignoreUrls = !string.IsNullOrEmpty(apiIgnore) ? apiIgnore.Split(",") : new string[] { "get" }; (context.RequestServices.GetService(typeof(RequestLogModel)) as RequestLogModel).RequestDate = DateTime.Now; try { // 存储请求数据 requestParam = RequestDataLog(context); context.Request.Body.Position = 0; } catch { } using MemoryStream ms = new(); context.Response.Body = ms; await _next(context); try { // 存储响应数据 responseParam = ResponseDataLog(context.Response); } catch { } ms.Position = 0; await ms.CopyToAsync(originalBody); if (!ignoreUrls.Any(x => context.Request.Path.Value?.Contains(x) ?? false)) { Logger.Add(requestParam, responseParam); } } catch (Exception ex) { // 记录异常 } finally { context.Response.Body = originalBody; } } else { await _next(context); } } private string RequestDataLog(HttpContext context) { var request = context.Request; var sr = new StreamReader(request.Body); object obj = new { QueryString = request.QueryString.ToString(), BodyData = sr.ReadToEndAsync().Result }; string data = JsonConvert.SerializeObject(obj); request.Body.Position = 0; return data; } private string ResponseDataLog(HttpResponse response) { response.Body.Position = 0; using StreamReader stream = new StreamReader(response.Body, leaveOpen: true); string body = stream.ReadToEnd(); response.Body.Position = 0; return body; } } }