Симптом
Точка маршрута, читающая тело запроса, при запросе без тела отвечает 500 с текстом внутреннего исключения:
POST /greeter/postjsonbody (без тела)
500 {Модуль .../hwapp/ИнтерактивныйКонтролПриветствия.os / Error in line: 18 / Value is not of object type}
POST /catalog/create (без тела)
500 {Модуль .../hwapp/КонтролКаталога.os / Error in line: 62 / Value is not of object type}
То же самое ждёт запрос с телом, но без заголовка Content-Type: application/json, и запрос с телом, которое не разобралось.
Причина
ВходящийЗапрос.ТелоЗапросаОбъект возвращает Неопределено, если тела нет или тип содержимого не JSON:
Функция ТелоЗапросаОбъект(ТипТелаЗапроса) Экспорт
Результат = Неопределено;
Если ЗначениеЗаполнено(Тело)
И СтрНайти(НРег(СокрЛП(Заголовки["Content-Type"])), "application/json") > 0 Тогда
Результат = Парсеры.ДесериализоватьJson(Тело, ТипТелаЗапроса);
КонецЕсли;
Возврат Результат;
КонецФункции
Дальше Неопределено уходит в точку маршрута, та обращается к полю, и исключение всплывает уже из прикладного кода. Обработчик ловит его общим Исключение и отдаёт 500.
Почему это неправильно
Ошибка на стороне клиента: он не прислал тело или прислал неразбираемое. По HTTP это 400, а не 500 - 500 говорит «сломался сервер» и в мониторинге читается как отказ сервиса.
Плюс в теле ответа уезжает внутренняя диагностика с путём к файлу и номером строки. Наружу такому лучше не попадать.
Отдельно неудобно, что автор точки маршрута обязан помнить про проверку сам, а забыть её ничего не мешает - и тогда вместо внятного отказа получается стектрейс.
Предложение
Отвечать 400 до вызова точки маршрута, если тело обязательно, но отсутствует или не разобралось.
Обязательность объявляется аннотацией &Заполнено на параметре тела - её уже читает генератор спецификации, чтобы выставить requestBody.required:
Процедура ЗавестиТовар(Ответ, &Заполнено &Тип("ТоварКаталога") ТелоЗапросаОбъект) Экспорт
Тогда объявление начнёт не только описывать, но и обеспечивать: requestBody.required в документе и проверка на входе будут говорить одно и то же. Сейчас документ обещает обязательность, за которой ничего не стоит.
Без &Заполнено поведение остаётся прежним - в точку маршрута приходит Неопределено, и разбираться с ним автору.
О чём не забыть
- Отличать «тела нет» от «тело есть, но не разобралось» - обе ситуации 400, но сообщения разные и это заметно помогает при отладке.
- Не отдавать наружу внутреннюю диагностику.
- Оба сервера должны вести себя одинаково. Общая точка -
ОбработчикЗапросов.СформироватьОтвет, где формируются параметры точки маршрута.
- Тесты на обоих серверах, нативном и прикладном.
Связано
- Аннотация
&Заполнено на параметре появилась в #124.
- Сам
validate ограничения на параметре метода не проверяет - autumn-library/autumn-validate#4. Здесь проверку делает winow, а не валидатор.
Симптом
Точка маршрута, читающая тело запроса, при запросе без тела отвечает 500 с текстом внутреннего исключения:
То же самое ждёт запрос с телом, но без заголовка
Content-Type: application/json, и запрос с телом, которое не разобралось.Причина
ВходящийЗапрос.ТелоЗапросаОбъектвозвращаетНеопределено, если тела нет или тип содержимого не JSON:Дальше
Неопределеноуходит в точку маршрута, та обращается к полю, и исключение всплывает уже из прикладного кода. Обработчик ловит его общимИсключениеи отдаёт 500.Почему это неправильно
Ошибка на стороне клиента: он не прислал тело или прислал неразбираемое. По HTTP это 400, а не 500 - 500 говорит «сломался сервер» и в мониторинге читается как отказ сервиса.
Плюс в теле ответа уезжает внутренняя диагностика с путём к файлу и номером строки. Наружу такому лучше не попадать.
Отдельно неудобно, что автор точки маршрута обязан помнить про проверку сам, а забыть её ничего не мешает - и тогда вместо внятного отказа получается стектрейс.
Предложение
Отвечать 400 до вызова точки маршрута, если тело обязательно, но отсутствует или не разобралось.
Обязательность объявляется аннотацией
&Заполненона параметре тела - её уже читает генератор спецификации, чтобы выставитьrequestBody.required:Тогда объявление начнёт не только описывать, но и обеспечивать:
requestBody.requiredв документе и проверка на входе будут говорить одно и то же. Сейчас документ обещает обязательность, за которой ничего не стоит.Без
&Заполненоповедение остаётся прежним - в точку маршрута приходитНеопределено, и разбираться с ним автору.О чём не забыть
ОбработчикЗапросов.СформироватьОтвет, где формируются параметры точки маршрута.Связано
&Заполненона параметре появилась в #124.validateограничения на параметре метода не проверяет - autumn-library/autumn-validate#4. Здесь проверку делает winow, а не валидатор.