Согласование содержимого. Введение

На сегодняшний день, практически форматом по умолчанию для отправки ответа клиенту сервером Web API считается JSON. Это действительно довольно популярный, лаконичный и простой формат обмена данными, который используется практически повсеместно.

Когда мы создаем приложение ASP.NET Core Web API, то, по умолчанию, сервер пытается сериализовать ответ в JSON. При этом ASP.NET Core позволяет настраивать формат данных ответа и использовать, в том числе, для обмена данными XML. В этой части мы рассмотрим некоторые вопросы форматирования данных ответа в приложениях ASP.NET Core Web API.

Заголовок Accept

Этот заголовок используется сервером для согласования содержимого и указывает серверу какие форматы данных может принимать клиент. Например, посмотрим на GET-запрос в http-файле проекта

GET {{WebApplication10_HostAddress}}/weatherforecast/
Accept: application/json

В заголовке Accept мы указали серверу, что готовы принять данные в формате JSON и сервер, используя один из предопределенных форматировщиков ответа, возвращает нам ответ в указанном формате. По умолчанию ASP.NET Core поддерживает следующие форматы данных, выраженные в виде MIME-типов:

  • application/json
  • text/json
  • text/plain

В целом, согласование содержимого между клиентом и сервером можно представить следующим образом

Если клиент передает в заголовке MIME-тип, для которого сервер не может найти подходящего форматировщика, то он, в зависимости от настроек, может либо вернуть код статуса HTTP 406 Not Acceptable, либо сформировать ответ, используя первый из найденных форматировщиков (обычно, это форматировщик JSON).

Отдельно стоит обратить внимание на то, как реагирует ASP.NET Core на запросы с заголовком Accept от браузера. По умолчанию ASP.NET Core полностью игнорирует заголовок Accept, если запрос отправлен из браузера и отправляет ответ в том формате, которое считается предпочтительным – это может быть и JSON и обычный текст и XML и так далее. Такое поведение позволяет обеспечить более согласованное взаимодействие между браузером и приложением ASP.NET Core.

Теперь рассмотрим вопросы, связанные с согласованием содержимого в приложении ASP.NET Core Web API.

Настройка ответов сервера

Первое, что нам необходимо сделать это определиться с двумя вопросами:

  1. Будем ли мы игнорировать заголовок Accept, полученный от браузера?
  2. Будем ли мы отклонять запросы на получение данных в формате, который не поддерживается сервером?

После ответа на эти вопросы мы можем настроить обработку запросов и формирование ответов сервера следующим образом

builder.Services.AddControllers(config =>
{
    config.RespectBrowserAcceptHeader = true;
    config.ReturnHttpNotAcceptable = true;
});

Здесь мы, используя делегат Action<MvcOptions> установили значение true для двух свойств:

  • RespectBrowserAcceptHeader – принимать и обрабатывать заголовки Accept из браузера
  • ReturnHttpNotAcceptable – возвращать код 406, если запрашиваемый формат данных ответа не поддерживается сервером.

Что касается браузеров, то они, обычно, отправляют в Accept довольно большое количество поддерживаемых форматов данных, поэтому работа нашего приложения при запросах из браузеров не поменяется – мы будем получать всё тот же ответ в формате JSON. Для проверки же работы по отправке ответа с кодом HTTP 406, добавим в http-файл проекта следующий запрос

GET {{WebApplication12_HostAddress}}/weatherforecast/
Accept: application/xml

Здесь мы пытаемся получить данные в формате XML. Попытка выполнить этот запрос приведет к следующему ответу сервера

Попробуйте установить свойству ReturnHttpNotAcceptable значение false и повторить запрос – вы увидите, что сервер вернет данные ответа, используя форматировщик по умолчанию, то есть в формате JSON.

Добавление и настройка форматировщиков ответов

Для добавления и настройки форматировщиков ответов в ASP.NET Core используются методы расширения для IMvcBuilder. Например, на данный момент, наше приложение не поддерживает формат XML – добавим такой форматировщик в наше приложение

builder.Services.AddControllers(config =>
{
    config.RespectBrowserAcceptHeader = true;
    config.ReturnHttpNotAcceptable = true;
})
.AddXmlSerializerFormatters();

Здесь мы воспользовались методом расширения AddXmlSerializerFormatters() для добавления форматировщика ответов в XML. Запустим приложение и снова проверим выполнение нашего нового запроса

Следует отдельно отметить, что для форматировщика XML обязательно требуется, чтобы класс сериализуемого объекта имел открытый конструктор без параметров.

Для настройки того или иного форматировщика ответов сервера предусмотрены методы расширения IMvcBuilder AddXmlOptions() и AddJsonOptions() в которые передаются соответствующие делегаты для установки тех или иных настроек.

Например, следующие фрагмент кода демонстрирует настройку форматировщика JSON

builder.Services.AddControllers(config =>
{
    config.RespectBrowserAcceptHeader = true;
    config.ReturnHttpNotAcceptable = true;
})
.AddXmlSerializerFormatters().AddJsonOptions(configure =>
{
    configure.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});

Ограничение форматирования ответов

Если требуется, чтобы определенное действие контроллера или весь контроллер целиком формировал ответ в определенном формате, то можно воспользоваться атрибутом [Produces], в котором указать MIME-типы выходных данных. Например, ограничим формат ответа в действии так, чтобы оно возвращало только JSON

[HttpGet]
[Produces("application/json ")]
public IEnumerable<WeatherForecast> Get()
{
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
    .ToArray();
}

Теперь, если пользователь запросит ответ в любом формате, а на сервере будет отключен отклик с кодом 406 на недопустимый формат, то пользователь будет получать ответ только в формате JSON вне зависимости от того какие форматировщики используются в приложении

Получение формата ответа из URI

Некоторые API, поддерживающие отправку ответов в различных форматах, позволяют указывать формат выходных данных непосредственно в URL. В ASP.NET Core поддерживается и такая возможность. Рассмотрим следующий пример действия контроллера

[HttpGet("{format?}")]
[FormatFilter]
public IEnumerable<WeatherForecast> Get()
{
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
    .ToArray();
}

Здесь в параметрах маршрута действия указан необязательный параметр format

[HttpGet("{format?}")]

А также определен специальный атрибут

[FormatFilter]

Теперь наше приложение будет формировать ответ в соответствии с правилами, указанными в таблице ниже

Путь запроса Значение параметра format Формат ответа
/weatherforecast По умолчанию (JSON)
/weatherforecast/json json JSON
/weatherforecast/xml xml XML (если этот форматировщик добавлен)
/weatherforecast/abcd abcd ­Ошибка 404 Not Found

Теперь попробуем запустить приложение и посмотреть ответы сервера при различных вариантах параметра:

Итого

Для согласования содержимого используется заголовок клиента Accept в котором клиент перечисляет принимаемые им форматы данных. В ASP.NET Core Web API мы можем добавлять различные форматировщики для формирования ответа, а также настраивать их. По умолчанию, ASP.NET Core Web API отклоняет заголовки Accept от браузеров.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии