Обработка ошибок в ядре asp.net (.net8), как получить URL-адрес, данные формы и IP-адрес клиента

Я создаю новый веб-сайт API в .NET8, который является последней версией ASP.NET Core.

В моем program.cs я добавил это:

builder.Services.AddExceptionHandler<ErrorHandler>();
app.UseExceptionHandler("/Home/Error");

В случае исключения это действительно относится к моему специальному классу обработки ошибок:

public class ErrorHandler : IExceptionHandler

Я получаю доступ к дополнительным данным, которые мне нужны, следующим образом:

private readonly ILogger<ErrorHandler> logger;
private readonly IHttpContextAccessor _httpContextAccessor;

public ErrorHandler(ILogger<ErrorHandler> logger, IHttpContextAccessor httpContextAccessor)
{
    this.logger = logger;
    this._httpContextAccessor = httpContextAccessor;
}

Пока все хорошо, но теперь я пытаюсь получить некоторые данные для своего журнала:

  1. URL-адрес запроса
  2. Данные формы (RAW)
  3. IP-адрес клиента
  4. реферер
    private string GetErrorReport(Exception e)
    {
        StringBuilder sbErrorReport = new StringBuilder(1024);
        try
        {
    
            HttpResponse response = _httpContextAccessor.HttpContext?.Response; 
            HttpRequest request = _httpContextAccessor.HttpContext?.Request; 
            string CurUrl = "";
            string CurReferrer = "";
            string formData = "";
            string clientIP = "";
    
            if (request != null)
            {
                CurUrl = request.GetEncodedPathAndQuery();
                CurReferrer = request.Headers["Referer"].ToString();
                if (request.Body != null)            //is this the same as request.Form.ToString()?
                {
                    using (StreamReader sr = new StreamReader(request.Body))
                    {
                        formData = sr.ReadToEnd();
                    }
                }
    
                if (request.HttpContext != null && request.HttpContext.Connection != null && request.HttpContext.Connection.RemoteIpAddress != null)
                {
                    clientIP = request.HttpContext.Connection.RemoteIpAddress.ToString();
                }
            }
    
        
        }
        catch (Exception ex)
        {
            //nothing?
        }
    
        return sbErrorReport.ToString();
    }

Никто из них, кажется, не работает...

CurUrl выдает «/Home/Error», а не исходный URL-адрес, в котором возникла ошибка. CurReferrer выдает ошибку о том, что заголовки недоступны. formData полностью выходит из строя. clientIP действительно работает, если ::1 подходит для локального хоста.

Есть идеи, как лучше всего записывать ошибки со всеми этими подробностями в файл журнала?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
180
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В действии обработчика ошибок вы можете получить подробную информацию об ошибке следующим образом:

var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();

Это позволит получить информацию об ошибке из текущего контекста. затем вы можете использовать exceptionHandlerFeature.Error, чтобы получить фактическую ошибку. например:

public string? ExceptionMessage { get; set; }

var exceptionHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();

var error = exceptionHandlerFeature.Error;

Вы также можете прочитать, где произошла ошибка (URL-адрес запроса) из свойства PathexceptionHandlerFeature следующим образом:

if (exceptionHandlerFeature.Path == "/")
{
    ExceptionMessage ??= string.Empty;
    ExceptionMessage += " Page: Home.";
}

HttpContext.Connection.RemoteIpAddress предоставит вам IP клиента. Фактически, вы можете получить текущего пользователя следующим образом:

if (context.User.Identity is { IsAuthenticated: true })
    userName = context.User.Identity.Name;

Обратите внимание, что у вас возникнут проблемы с получением IP-адреса, если ваш сервер расположен за балансировщиком нагрузки или если имеется прокси-сервер.

HttpContext.Request.Form предоставит вам данные формы. Request.Headers["Referer"].ToString() даст вам значение заголовка реферера.

Кстати, вы можете использовать встроенный обработчик для обработки ошибок, примерно так:

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler(exceptionHandlerApp =>
    {
        exceptionHandlerApp.Run(async context =>
        {
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
            var errorCode = Guid.NewGuid().ToString();
            var exceptionHandlerFeature =
                context.Features.Get<IExceptionHandlerFeature>();

            // do stuff

            context.Response.Redirect("/error?customErrorCode = " + errorCode); // perform 302 redirection with error code in query string
        });
    });

    app.UseHsts(); // you can configure any other non-development features in this if block too, like hsts or https redirection (note that you can do can set up these two in IIS too, although irrelevant)
}

см. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-8.0 для получения дополнительной информации об обработке ошибок в ядре asp.net со встроенной ошибкой. промежуточное программное обеспечение обработчика.

Получение IP-адреса клиента и Referer работает. Однако получение данных формы не работает. Мне нужны необработанные данные, отправленные POST на веб-страницу, для последующего анализа ошибок. Я попробовал и req.Form, и req.Body. req.Form не работает и выдает предупреждение: вызов этого свойства может привести к исчерпанию потока, поскольку оно является оберткой асинхронной реализации.

Leo Muller 12.05.2024 15:38

возможно попробую await context.Request.ReadFormAsync();, а возможно await new StreamReader(context.Request.Body).ReadToEndAsync();

Emre Bener 13.05.2024 12:38

StreamReader(context.Request.Body).ReadToEndAsync() должен работать, но это не так.

Leo Muller 13.05.2024 14:56

вы уверены, что в теле запроса действительно что-то есть? проверьте вкладку сети в devtools и проверьте запрос

Emre Bener 14.05.2024 08:58

да, я делаю запрос с почтальоном. в действии данные появляются без проблем

Leo Muller 15.05.2024 09:00

После огромной помощи Эмре Бенера, спасибо вам за это, я понял это. Моя ошибка заключалась в том, что я попытался использовать IHttpContextAccessor, хотя все, что мне было нужно, уже было в TryHandleAsync из IExceptionHandler.

Вот мой код, который работает: В program.cs:

builder.Services.AddExceptionHandler<ErrorHandler>();   //custom error log, still needs UseExceptionHandler
var app = builder.Build();
app.UseExceptionHandler("/Home/Error");

И в моем общем классе обработки исключений ErrorHandler.cs:

public class ErrorHandler : IExceptionHandler
{

    public ErrorHandler()
    {

    }

    public ValueTask<bool> TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {

        string errorReport = GetErrorReport(exception, httpContext);
        SaveError(errorReport);

        return ValueTask.FromResult(false);
    }



    private string GetErrorReport(Exception e, HttpContext httpContext)
    {
        StringBuilder sbErrorReport = new StringBuilder(1024);
        try
        {

            string errorMessage;
            string CurUrl = "";
            string CurReferrer = "";
            string reqBodyRaw = "";
            string clientIP = "";
            string extra = "";

            var exceptionHandlerFeatures = httpContext.Features.Get<IExceptionHandlerFeature>();

            //error message:
            errorMessage = e.Message;   //also check e.InnerException

            //client IP
            if (httpContext.Connection.RemoteIpAddress != null)
            {
                clientIP = httpContext.Connection.RemoteIpAddress.ToString();
            }

            //Referer / headers:
            CurReferrer = httpContext.Request.Headers["Referer"].ToString();


            //request posted body 
            using (var reader = new StreamReader(httpContext.Request.BodyReader.AsStream(false), Encoding.UTF8))
            {
                reqBodyRaw = reader.ReadToEnd();
            }

            //get the requested URL
            if (exceptionHandlerFeatures != null)
            {
                //CurUrl = httpContext.Request.Path;  //this does not work, gives the error page path.
                CurUrl = exceptionHandlerFeatures.Path; //this does work.
            }

        // write details to sbErrorReport....
            
        }
        catch (Exception ex)
        {
            //nothing?
        }

        return sbErrorReport.ToString();
    }
}

Другие вопросы по теме