1
dengjunjie
2025-09-29 d9c99e0480b4910cdb134778dd5c314b35ec4cf2
ÏîÄ¿´úÂë/WMS/WIDESEA_WMSServer/WIDESEA_Core/Middlewares/ApiLogMiddleware.cs
@@ -1,9 +1,11 @@
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;
@@ -21,27 +23,63 @@
        /// 
        /// </summary>
        private readonly RequestDelegate _next;
        private readonly ILogger<ApiLogMiddleware> _logger;
        public ApiLogMiddleware(RequestDelegate next)
        public ApiLogMiddleware(RequestDelegate next, ILogger<ApiLogMiddleware> 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
                    {
                        // å­˜å‚¨è¯·æ±‚数据
                        await RequestDataLog(context);
                        requestParam = RequestDataLog(context);
                        context.Request.Body.Position = 0;
                    }
                    catch { }
@@ -53,18 +91,19 @@
                    try
                    {
                        // å­˜å‚¨å“åº”数据
                        ResponseDataLog(context.Response, ms);
                        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
                {
@@ -77,61 +116,102 @@
            }
        }
        /// <summary>
        /// è¿”回过期响应
        /// </summary>
        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
            };
        private async Task RequestDataLog(HttpContext context)
            var jsonString = JsonConvert.SerializeObject(json);
            await context.Response.WriteAsync(jsonString);
        }
        /// <summary>
        /// è¿”回到期警告响应(可选)
        /// </summary>
        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);
        }
        /// <summary>
        /// åˆ¤æ–­æ˜¯å¦è·³è¿‡æ—¥å¿—记录
        /// </summary>
        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);
            //long length = request.Body.Length;
            RequestLogInfo requestResponse = new RequestLogInfo()
            {
                Path = request.Path,
                QueryString = request.QueryString.ToString(),
                BodyData = await sr.ReadToEndAsync()
            };
            var content = JsonConvert.SerializeObject(requestResponse);
            if (!string.IsNullOrEmpty(content))
            {
                LogLock.OutLogAOP("接口日志", new string[] { "请求数据 -  è¯·æ±‚数据类型:" + requestResponse.GetType().ToString(), content });
                request.Body.Position = 0;
            }
        }
        private void ResponseDataLog(HttpResponse response, MemoryStream ms)
        {
            ms.Position = 0;
            var responseBody = new StreamReader(ms).ReadToEnd();
            // å޻除 Html
            var reg = "<[^>]+>";
            var isHtml = Regex.IsMatch(responseBody, reg);
            if (!string.IsNullOrEmpty(responseBody))
            object obj;
            string bodyData = sr.ReadToEndAsync().Result;
            if (request.ContentLength <= 100000)
            {
                Parallel.For(0, 1, e =>
                obj = new
                {
                    LogLock.OutLogAOP("接口日志", new string[] { "响应数据 -  å“åº”数据类型:" + responseBody.GetType().ToString(), responseBody });
                });
                    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;
        }
    }
    public class RequestLogInfo
    {
        /// <summary>
        /// è¯·æ±‚地址
        /// </summary>
        public string Path { get; set; }
        /// <summary>
        /// è¯·æ±‚参数
        /// </summary>
        public string QueryString { get; set; }
        /// <summary>
        /// Body参数
        /// </summary>
        public string BodyData { get; set; }
        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 "";
        }
    }
}