using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Org.BouncyCastle.Asn1.Ocsp; 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; private readonly ILogger _logger; public ApiLogMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } //todo public async Task InvokeAsync(HttpContext context) { //if (App.ExpDateTime != null) //{ // if ((DateTime.Now - App.ExpDateTime.GetValueOrDefault()).TotalSeconds > 0) // { // await ReturnExpiredResponse(context, "系统已过期,请联系管理员"); // return; // } // //var Hours = (App.ExpDateTime.GetValueOrDefault() - DateTime.Now).TotalHours; // //if (Hours < 72) // //{ // // // 记录警告日志 // // _logger.LogWarning($"系统即将到期,剩余时间:{Hours:F2}小时,到期时间:{App.ExpDateTime.GetValueOrDefault():yyyy-MM-dd HH:mm:ss}"); // // // 在响应头中添加到期提示 // // context.Response.Headers.Add("X-Expiration-Warning", // // $"系统将在 {Hours:F2} 小时后到期 ({App.ExpDateTime.GetValueOrDefault():yyyy-MM-dd HH:mm:ss})"); // // // 如果需要直接返回提示信息,取消下面的注释 // // await ReturnExpirationWarningResponse(context, Hours); // // return; // //} //} // 过滤,只有接口 if (context.Request.Path.Value?.Contains("api") ?? false) { if (App.ExpDateTime != null) { if ((DateTime.Now - App.ExpDateTime.GetValueOrDefault()).TotalSeconds > 0 && !context.Request.Path.Value.Contains("getVierificationCode") && context.Request.Path.Value != "/api/User/login") { await ReturnExpiredResponse(context, "系统已过期,请联系管理员"); return; } } context.Request.EnableBuffering(); Stream originalBody = context.Response.Body; string requestParam = string.Empty; string responseParam = string.Empty; try { (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 (!ShouldSkipLogging(context.Request.Path.Value)) Logger.Add(requestParam, responseParam); } catch (Exception ex) { // 记录异常 } finally { context.Response.Body = originalBody; } } else { await _next(context); } } /// /// 返回过期响应 /// private async Task ReturnExpiredResponse(HttpContext context, string message) { context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; context.Response.ContentType = "application/json; charset=utf-8"; context.Response.Headers.ContentType= "application/json; charset=utf-8"; var json = new WebResponseContent { Message = message, Code = 500 }; var jsonString = JsonConvert.SerializeObject(json); await context.Response.WriteAsync(jsonString); } /// /// 返回到期警告响应(可选) /// private async Task ReturnExpirationWarningResponse(HttpContext context, double hoursRemaining) { context.Response.StatusCode = (int)HttpStatusCode.OK; context.Response.ContentType = "application/json"; var expirationDate = App.ExpDateTime.GetValueOrDefault(); var response = new { Code = 200, Message = "系统即将到期警告", Data = new { HoursRemaining = hoursRemaining, ExpirationDate = expirationDate, FormattedMessage = $"系统将在 {Math.Ceiling(hoursRemaining)} 小时后到期,到期时间:{expirationDate:yyyy-MM-dd HH:mm:ss}。请联系管理员续期。" }, Warning = true }; var jsonString = JsonConvert.SerializeObject(response); await context.Response.WriteAsync(jsonString); } /// /// 判断是否跳过日志记录 /// private bool ShouldSkipLogging(string path) { if (string.IsNullOrEmpty(path)) return false; var skipKeywords = new[] { "get", "Get", "query", "Query", "DownLoadApp", "downLoadApp", "UploadApp", "uploadApp" }; return skipKeywords.Any(keyword => path.Contains(keyword, StringComparison.OrdinalIgnoreCase)); } private string RequestDataLog(HttpContext context) { var request = context.Request; var sr = new StreamReader(request.Body); object obj; string bodyData = sr.ReadToEndAsync().Result; if (request.ContentLength <= 100000) { obj = new { QueryString = request.QueryString.ToString(), BodyData = bodyData }; } else { obj = new { QueryString = request.QueryString.ToString(), BodyData = "" }; } string data = JsonConvert.SerializeObject(obj); request.Body.Position = 0; return data; } private string ResponseDataLog(HttpResponse response) { if (response.ContentLength <= 100000) { response.Body.Position = 0; using StreamReader stream = new StreamReader(response.Body, leaveOpen: true); string body = stream.ReadToEnd(); response.Body.Position = 0; return body; } return ""; } } }