using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using System; using System.IO; using System.Text; using System.Threading.Tasks; using VOL.Core.Enums; using VOL.Core.Services; namespace VOL.Core.Middleware { /// /// 接口输入输出日志中间件 /// public class RequestResponseLoggingMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public RequestResponseLoggingMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { DateTime now = DateTime.Now; // Log the request var request = await HttpRequestResponseFormat.FormatRequest(context.Request); _logger.LogInformation($"HTTP Request Information:{Environment.NewLine}{now} {request}"); // Copy a pointer to the original response body stream var originalBodyStream = context.Response.Body; // Create a new memory stream to hold the response body using (var responseBody = new MemoryStream()) { context.Response.Body = responseBody; await _next(context); // Log the response string response = await HttpRequestResponseFormat.FormatResponse(context.Response); Logger.OK(LoggerType.Info, request, response); _logger.LogInformation($"HTTP Response Information:{Environment.NewLine}{now} {response}"); // Copy the contents of the new memory stream (which contains the response) to the original stream await responseBody.CopyToAsync(originalBodyStream); } } } public sealed class HttpRequestResponseFormat { public static async Task FormatRequest(HttpRequest request) { request.EnableBuffering(); // 二进制内容判断可保留 if (request.ContentType != null && (request.ContentType.Contains("multipart/form-data") || request.ContentType.Contains("application/octet-stream"))) { return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} [二进制数据不可读]"; } using var reader = new StreamReader(request.Body, Encoding.UTF8, leaveOpen: true); var bodyAsText = await reader.ReadToEndAsync(); request.Body.Position = 0; return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}"; } public static async Task FormatResponse(HttpResponse response) { response.Body.Seek(0, SeekOrigin.Begin); if (response.ContentType != null && response.ContentType.Contains("application/octet-stream")) { return $"StatusCode: {response.StatusCode}, Body: 二进制数据不可读"; } using var reader = new StreamReader(response.Body, Encoding.UTF8, leaveOpen: true); var text = await reader.ReadToEndAsync(); response.Body.Seek(0, SeekOrigin.Begin); return $"StatusCode: {response.StatusCode}, Body: {text}"; } } }