Содержание
На сегодняшний день, практически форматом по умолчанию для отправки ответа клиенту сервером 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.
Настройка ответов сервера
Первое, что нам необходимо сделать это определиться с двумя вопросами:
- Будем ли мы игнорировать заголовок
Accept
, полученный от браузера? - Будем ли мы отклонять запросы на получение данных в формате, который не поддерживается сервером?
После ответа на эти вопросы мы можем настроить обработку запросов и формирование ответов сервера следующим образом
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
от браузеров.