Scalatra: печать кода состояния HTTP всех API

У меня есть сервлет scalatra с несколькими REST API. Для ведения журнала я использую метод after() для вывода кода состояния возврата после вызова каждого API.

after() {
  logger.info("request {} {} returned with status code {}", request.getMethod, request.getRequestURL, response.getStatus.toString)
}

Я заметил, что когда метод возвращается с halt, код состояния печатается правильно, но когда метод возвращает код состояния в последней строке (без halt), код состояния, который будет напечатан, всегда будет 200, независимо от реального статус возвращен.

Например:

post("/users/:user") {

  try {

    //some logic here...
    if(condition)
     halt(InternalServerError("DB error"))  //this will cause status 500 to be printed in the 'after' method


  } catch {
    case e: Exception =>
      InternalServerError("an unknown error occurred") //this will cause status 200 to be printed in the 'after' method
  }
}

В обоих случаях пользователь получает реальный код состояния (500).

Любая идея, почему это происходит? Это ошибка? Я разместил этот вопрос в списке рассылки scalatra-user, но этот список, похоже, совершенно неактивен.

Ализа


person Aliza    schedule 03.03.2016    source источник


Ответы (1)


(отказ от ответственности: я не разработчик Scalatra, но я использовал его для проекта. Это основано на том, что я некоторое время назад читал код.)

Это связано с тем, как Scalatra обрабатывает выброшенные исключения (соответствующий код, кажется, начинается с этот). Если где-то в runActions возникнет исключение (halt выдает HaltException), будет вызван блок catch из cradleHalt, и мы перейдем к renderHaltException, который установит код состояния ответа.

Это не совсем то же самое, когда вы не вызываете halt, а возвращаете ActionResult напрямую. В этом случае executeRoutes создает значение, которое затем передается renderResponse, который затем вызывает renderResponseBody и, наконец, renderPipeline. Этот блок похоже, это место, где действительно устанавливается фактический код состояния из ActionResult. Однако функция after уже вызвана (она была вызвана в actionResult до возврата из executeRoutes). Итак, вы получаете именно ваше поведение: когда вы не используете halt, правильный статус ответа устанавливается только в фактическом ответе, но не в вашем вызове журнала.

Вы, вероятно, пробовали это, но быстрое исправление того, что ваш InternalServerError не генерирует правильный код состояния HTTP при входе в систему, заключается в том, чтобы просто обернуть его в другой вызов halt.

Насчет того, является ли это ошибкой, я не могу сказать. Я предполагаю, что, вероятно, нет, потому что в документации executeRoutes было сказано, что after вызывается до того, как actionResult передается в renderResponse. Что было неясно, так это то, что акт рендеринга actionResult также устанавливает код ошибки HTTP, который вы хотели зарегистрировать ранее.

Вы должны будете подтвердить с ними на том, что :).

person bow    schedule 13.03.2016
comment
Спасибо за подробное объяснение. Я открыл ошибку, но еще не получил от них известий. Мой обходной путь на данный момент заключается в том, чтобы обернуть все с помощью halt(). - person Aliza; 13.03.2016