You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
3.1 KiB
103 lines
3.1 KiB
1 week ago
|
using CoreAgent.Infrastructure.Options;
|
||
|
using Microsoft.AspNetCore.Http;
|
||
|
using Microsoft.Extensions.Logging;
|
||
|
using Microsoft.Extensions.Options;
|
||
|
using System.Text;
|
||
|
|
||
|
namespace CoreAgent.Infrastructure.Middleware
|
||
|
{
|
||
|
public class ResponseLoggingMiddleware
|
||
|
{
|
||
|
private readonly RequestDelegate _next;
|
||
|
private readonly ILogger<ResponseLoggingMiddleware> _logger;
|
||
|
private readonly RequestLoggingOptions _options;
|
||
|
|
||
|
public ResponseLoggingMiddleware(
|
||
|
RequestDelegate next,
|
||
|
ILogger<ResponseLoggingMiddleware> logger,
|
||
|
IOptions<RequestLoggingOptions> options)
|
||
|
{
|
||
|
_next = next;
|
||
|
_logger = logger;
|
||
|
_options = options.Value;
|
||
|
}
|
||
|
|
||
|
public async Task InvokeAsync(HttpContext context)
|
||
|
{
|
||
|
if (ShouldSkipLogging(context))
|
||
|
{
|
||
|
await _next(context);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 保存原始响应流
|
||
|
var originalBodyStream = context.Response.Body;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
// 创建一个新的内存流来捕获响应
|
||
|
using var responseBody = new MemoryStream();
|
||
|
context.Response.Body = responseBody;
|
||
|
|
||
|
// 继续处理请求
|
||
|
await _next(context);
|
||
|
|
||
|
// 读取响应内容
|
||
|
responseBody.Seek(0, SeekOrigin.Begin);
|
||
|
var response = await ReadResponseBodyAsync(responseBody);
|
||
|
|
||
|
// 记录响应
|
||
|
_logger.LogInformation(
|
||
|
"Response for {Method} {Path}: {StatusCode} - {Response}",
|
||
|
context.Request.Method,
|
||
|
context.Request.Path,
|
||
|
context.Response.StatusCode,
|
||
|
response);
|
||
|
|
||
|
// 将响应写回原始流
|
||
|
responseBody.Seek(0, SeekOrigin.Begin);
|
||
|
await responseBody.CopyToAsync(originalBodyStream);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
// 确保响应体被恢复
|
||
|
context.Response.Body = originalBodyStream;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private bool ShouldSkipLogging(HttpContext context)
|
||
|
{
|
||
|
if (!_options.LogResponseBody)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (_options.ExcludePaths.Any(p => context.Request.Path.StartsWithSegments(p)))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (_options.ExcludeMethods.Contains(context.Request.Method))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private async Task<string> ReadResponseBodyAsync(Stream responseBody)
|
||
|
{
|
||
|
using var reader = new StreamReader(
|
||
|
responseBody,
|
||
|
encoding: Encoding.UTF8,
|
||
|
detectEncodingFromByteOrderMarks: false,
|
||
|
bufferSize: 1024 * 45,
|
||
|
leaveOpen: true);
|
||
|
|
||
|
var body = await reader.ReadToEndAsync();
|
||
|
return body.Length > _options.MaxResponseBodySize
|
||
|
? body.Substring(0, _options.MaxResponseBodySize) + "..."
|
||
|
: body;
|
||
|
}
|
||
|
}
|
||
|
}
|