【问题标题】:Log request payloads in .NET Core 3在 .NET Core 3 中记录请求负载
【发布时间】:2020-03-11 23:19:54
【问题描述】:

我最近将一个 API 升级到 .NET Core 3,据我所知,升级后该位停止工作。

我想记录异常和通过请求正文传入的 json 有效负载。此 ExceptionLogger 作为过滤器插入以全局处理错误:

public class ExceptionLogger
{
    private readonly IServiceScopeFactory _factory;

    public ExceptionLogger(IServiceScopeFactory factory)
    {
        _factory = factory;
    }   

    public async Task<Guid?> LogException(Exception ex)
    {
        using var scope = _factory.CreateScope();
        var accessor = scope.ServiceProvider.GetRequiredService<IHttpContextAccessor>();
        var displayUrl = accessor?.HttpContext?.Request?.GetDisplayUrl();
        var payload = await RetrievePayload(accessor, displayUrl);

        // ... code proceeds to log the exception, including the payload.
    }

    private async Task<string> RetrievePayload(IHttpContextAccessor accessor, string displayUrl)
    {
        accessor.HttpContext.Request.EnableBuffering();
        accessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
        using var sr = new System.IO.StreamReader(accessor.HttpContext.Request.Body);

        return await sr.ReadToEndAsync(); // The request body is always empty now....!
    }
}

accessor 有查询字符串和表单参数,甚至accessor.HttpContext.Request.ContentLength 也有一个值表明有效负载在那里。但是,Request.Body 流是空的,即使在我重置光标位置之后也是如此。

此时我如何获取请求正文?

【问题讨论】:

    标签: c# asp.net-core .net-core-3.0


    【解决方案1】:

    这是 .net core 3.0 的内容。如果您在为此配置它之前尝试多次读取该正文,它将在第一次读取时成功,并且在随后的读取中将失败。因此,您需要一个中间件来配置该主体以进行多次读取。正如here 所提到的,request.EnableRewind() 可以解决该标记请求,并且正如 here 所提到的,您需要将对 EnableRewind 的任何调用更改为 EnableBuffering。因此,如果我们退回您的案例,您的错误处理程序应如下所示:

        public class ErrorLoggingMiddleware
    {
        private readonly RequestDelegate next;
    
        public ErrorLoggingMiddleware(RequestDelegate next)
        {
            this.next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            try
            {
                context.Request.EnableBuffering(); // this part is crucial
                await this.next(context);
            }
            catch (Exception e)
            {
    
                var stream = context.Request.Body;
                stream.Seek(0, SeekOrigin.Begin);
                using var reader = new StreamReader(stream);
                var bodyString =  await reader.ReadToEndAsync();
    
    
                // log the error
            }
        }
    }
    

    或者,您可以先将中间件分成两部分,以进行第一个链接中提到的倒带。因为它必须在第一次读取到正文之前运行。 (需要先在 StartUp.cs 配置中注册)然后你可以注册你的错误记录中间件或者你也可以使用过滤器,因为我们已经启用了 body 进行多次读取。

    【讨论】:

    • 太好了,谢谢。有用。我在中间件类中使用 request.EnableReview ,但无法让它工作。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-10
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    相关资源
    最近更新 更多