.NET Core Web API: вернуть пользовательский код состояния HTTP с типом контента application/problem+json

ControllerBase содержит такие методы, как Conflict(), которые возвращают объект ConflictResult (представляющий ответ HTTP 409), производный от StatusCodeResult. Результирующее тело ответа имеет тип содержимого application/problem+json и выглядит следующим образом:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
    "title": "Conflict",
    "status": 409,
    "traceId": "0HLO99QHFC9QI:00000001"
}

Для ответа HTTP 410 нет встроенного метода/класса, поэтому я сделал его:

[DefaultStatusCode(410)]
public class GoneResult : StatusCodeResult
{
    public GoneResult() : base(410)
    {}
}
...
public static class ControllerBaseExtensions
{
    public static GoneResult Gone(this ControllerBase controllerBase) // this doesn't give all the problem+JSON attributes
    {
        return new GoneResult();
    }
}

Однако это дает

{
    "type": "about:blank",
    "status": 410
}

то есть значение type отличается, а поля title и traceId отсутствуют.

Я также хотел бы создать собственный класс для ответа HTTP 500, который включает поле message с сообщением об ошибке. Я пытался вернуть StatusCode(StatusCodes.Status500InternalServerError), что дает мне тот же минимальный ответ application/problem+json, что и мой метод Gone(); Я также пытался вернуть StatusCode(StatusCodes.Status500InternalServerError, message), что дает мне сообщение об ошибке, но форматирует ответ как text/plain.

Два вопроса, которые вы задали здесь, имеют разные решения (imo). Я добавил ответ, касающийся вопроса 410, но другой ответ, который у вас есть (на момент написания этой статьи), касается вопроса 500. Я не вижу особого смысла в решении второго вопроса в ответе, который я дал, так как он обычно просто повторяет вторую половину другого ответа (я бы предпочел не возвращать явные 500, а использовать исключения и встроенный материал обработчика исключений, но это только мое мнение).

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

Ответы 2

Просто вы должны вернуть тело ответа ProblemDetails. Мне пришлось бы копаться в коде, чтобы быть уверенным, но я думаю, что ASP.NET Core делает это через промежуточное ПО только для определенных результатов. Они сказать что-либо в диапазоне 4xx, но я думаю, что на самом деле это просто ограничено встроенными типами результатов, которые возвращают коды состояния в этом диапазоне, а не результатом Любые с кодом состояния 4xx. Опять же, это предположение, поскольку я не смотрел, что именно они делают, хотя это не происходит как часть фактического результирующего класса.

Для ваших целей есть несколько способов справиться с этим. Вы можете написать собственное промежуточное ПО, чтобы перехватывать исходящие ответы и переписывать их. Вы можете использовать собственный обработчик исключений. Вместо этого вы можете просто наследоваться от ObjectResult, а затем просто создать экземпляр ProblemDetails самостоятельно и поместить его в базу. Вы даже можете просто вернуть ProblemDetails прямо из своего действия (хотя это, очевидно, наименее оптимальный способ).

Большое спасибо, Крис. Для 500 ошибок я реализовал собственный обработчик исключений и использовал пакет nuget.org/packages/Hellang.Middleware.ProblemDetails для тяжелой работы — теперь он работает хорошо.

Ed Graham 16.07.2019 16:03
Ответ принят как подходящий

Код, генерирующий ответ ProblemDetails, не знает о коде состояния 410, поэтому у него нет связанных свойств Link и Title, которые можно использовать при построении объекта ответа. Чтобы добавить эту осведомленность, настройте ApiBehaviorOptions в ConfigureServices следующим образом:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.ClientErrorMapping[410] = new ClientErrorData
    {
        Title = "Gone",
        Link = "https://tools.ietf.org/html/rfc7231#section-6.5.9"
    };
});

ClientErrorMapping — это словарь от int (код состояния) до ClientErrorData. Обратите внимание, что значение, которое я использовал для Link выше, действительно указывает на правильный раздел RFC.

Хороший. Я подумал, что есть какой-то способ сделать это, но ничего не нашел в документах или исходниках. Хотя, конечно, я не тратил кучу времени на поиски. Из любопытства, у вас есть источник для дальнейшего использования?

Chris Pratt 16.07.2019 16:13

@ChrisPratt В документах есть это, а в исходном коде 2.2 есть это. Есть также фабрика.

Kirk Larkin 16.07.2019 16:18

Спасибо. Я вчера буквально просматривал страницу из документов и все равно как-то пропустил ее. Шиш.

Chris Pratt 16.07.2019 16:21

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