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 "";
}
}
}