如何从HttpContext获取请求体

问题描述 投票:0回答:1

我尝试从 ASP.NET Core 8.0 Web API 中的过滤器访问请求正文,但请求正文始终为空,即使我传递正文也是如此。

过滤器:

using Azure.Core;
using backend.Log;
using backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace backend.Filters;

public class ExceptionFilter : IActionFilter, IOrderedFilter
{
    public int Order => int.MaxValue - 10;

    public void OnActionExecuting(ActionExecutingContext context) { }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        if (context.Exception is Exception exception)
        {
            HttpRequest request = context.HttpContext.Request;

            RequestLog.Log(exception, request);

            context.Result = new ObjectResult(GenerateResponseBody(exception))
            {
                StatusCode = 500,
            };

            context.ExceptionHandled = true;
        }
    }

    private static object GenerateResponseBody(Exception exception)
    {
        string message = "Erro inesperado no servidor.";

        if (exception.Message != null)
        {
            message += " " + exception.Message;
        }

        return new
        {
            message,
            variant = RequestVariant.Error.ToString(),
        };
    }
}

请求日志:

using System.IO.Pipelines;
using System.Text.Json;
using Microsoft.Extensions.Primitives;

namespace backend.Log;

public class RequestLog
{
    public static void Log(Exception exception, HttpRequest request)
    {
        request.EnableBuffering();

        DateTime dateTime = DateTime.Now;

        string requestPath = request.Path;
        string requestMethod = request.Method;

        List<KeyValuePair<string, StringValues>> requestQuery = request
            .Query.ToList<KeyValuePair<string, StringValues>>();

        List<KeyValuePair<string, StringValues>> requestHeaders = request
            .Headers.ToList<KeyValuePair<string, StringValues>>();

        Stream requestBody = request.Body;

        string exceptionMessage = exception.Message;
        string exceptionStackTrace = exception.StackTrace;

        string logText = "";

        logText += "DateTime: " + dateTime.ToString("dd/MM/yyyy HH:mm:ss") + "\n";

        logText += "Request:\n";
        logText += "\tPath: " + requestPath + "\n";
        logText += "\tMethod: " + requestMethod + "\n";

        string requestQueryLogText = GenerateRequestQueryLogText(requestQuery);

        logText += requestQueryLogText;

        string requestHeadersLogText = GenerateRequestHeadersLogText(requestHeaders);

        logText += requestHeadersLogText;

        string requestBodyLogText = GenerateRequestBodyLogText(requestBody);

        logText += requestBodyLogText;

        logText += "Exception:\n";
        logText += "\tMessage: " + exceptionMessage + "\n";
        logText += "\tStackTrace: " + exceptionStackTrace + "\n\n";

        using (StreamWriter writer = new StreamWriter("error.log", true))
        {
            writer.WriteLine(logText);
        }
    }

    private static string GenerateRequestQueryLogText(List<KeyValuePair<string, StringValues>> requestQuery)
    {
        string logText = "\tQuery:\n";

        requestQuery.ForEach((KeyValuePair<string, StringValues> e) =>
        {
            logText += "\t\t" + e.Key + ": " + e.Value + "\n";
        });

        return logText;
    }

    private static string GenerateRequestHeadersLogText(List<KeyValuePair<string, StringValues>> requestHeaders)
    {
        string logText = "\tHeaders:\n";

        requestHeaders.ForEach((KeyValuePair<string, StringValues> e) =>
        {
            logText += "\t\t" + e.Key + ": " + e.Value + "\n";
        });

        return logText;
    }

    private static string GenerateRequestBodyLogText(Stream requestBody)
    {
        string logText = "\tBody:\n";

        requestBody.Seek(0, SeekOrigin.Begin);

        using (StreamReader reader = new StreamReader(requestBody))
        {
            while (!reader.EndOfStream)
            {
                string line = reader.ReadLine();

                logText += "\t\t" + line + "\n";
            }
        }

        return logText;
    }
}

基本上每次控制器抛出异常时,过滤器都会捕获它,然后记录错误。

当它记录错误时,它会捕获请求的每个部分和异常并将其放入日志错误文件中。一切都很好,但是,当它到达请求正文时,即使不是,它也是空的。

当我运行以下请求时:

{ "login": "login", "password": "password" }

它将以下内容放入 error.log 中:

DateTime: 22/03/2024 17:43:00

Request:
    Path: /auth/sign-in
    Method: POST
    Query:
    Headers:
        Accept: application/json
        Connection: close
        Host: localhost:5071
        User-Agent: axios/1.6.7
        Accept-Encoding: gzip, compress, deflate, br
        Content-Type: application/json
        Content-Length: 58
        request-start-time: 1711140180634

    Body:
        
Exception:

    Message: testando log

    StackTrace:    at backend.Controllers.AuthController.SignIn(SignInDTO signInDTO) in C:\Users\jhose\desktop\projetos\day-manager\backend\Controllers\AuthController.cs:line 24
   at lambda_method3(Closure, Object, Object[])
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
c# rest asp.net-core asp.net-core-webapi .net-8.0
1个回答
0
投票

OnActionExecuting
/
OnActionExecuted
来不及启用缓冲,您需要尽早执行此操作。例如,您可以在中间件管道的开头某处添加类似以下内容:

app.Use(async (context, next) =>
{
    context.Request.EnableBuffering();
    await next();
});

虽然您可以做到这一点并且它可以工作(如果放置正确),但我建议考虑使用内置方法来记录主体/异常处理。查看更多:

  1. ASP.NET Core 中的 HTTP 日志记录
  2. 处理 ASP.NET Core 中的错误
  3. 如何在 ASP.NET Core 中间件中获取传入请求正文和传出响应正文?
© www.soinside.com 2019 - 2024. All rights reserved.