2016-01-02 5 views
1

Я использую Scala с Play для моего микросервиса. Он имеет контроллер, который использует конструкцию Action.async с пользовательским парсером тела. Вот пример кода:Scala Play - Action.async с BodyParser - Обработка исключений

def crud(param: String) = Action.async(SomeCustomBodyParser) { implicit request => 
    try { 
     <some code> 
    } catch { 
     case _ => <Exception Handling logic> 
    } 
} 

Проблема с этим кодом является то, что в случае исключения в SomeCustomBodyParser, он не получает обрабатываются в блоке поймать. Я попробовал несколько подходов, где я извлекаю его на внешний вид, а затем обрабатываю его вручную, но исключение не поймано правильно. Код Action.async предполагает, что он принимает блок кода и выполняет его отдельный контекст. Я не совсем точно понимаю, как это работает.

Как я могу обработать исключение и выплюнуть лучшее сообщение об исключении.

ответ

1

Action.async должен быть предоставлен Future[Result], который может быть выполнен либо с успешным Result, либо сбой.

Любое failedFuture есть ошибка HTTP-ответа.

Action.async { Future.failed(new Exception("Foo") } 

Способ такой ошибки в форматировании может быть выполнен в цистомизированном виде.

0

Если ваш BodyParser выдает исключение или не работает по какой-либо другой причине, тогда любой код внутри Action не будет выполняться. Характер async здесь не имеет отношения.

Например, System.exit в коде ниже никогда не работает как BodyParser всегда возвращает исключение.

package controllers 

import javax.inject.Inject 

import play.api.mvc._ 

import scala.concurrent.Future 

class Application @Inject() extends Controller { 

    def crud(param: String) = Action.async(
    parse.error[String](Future.failed(new RuntimeException("oh noes!"))) 
) { req => 
    System.exit(0) 
    ??? 
    } 

} 

Этот код генерирует этот StackTrace:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[RuntimeException: oh noes!]] 
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:254) ~[play_2.11-2.4.0.jar:2.4.0] 
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:180) ~[play_2.11-2.4.0.jar:2.4.0] 

И StackTrace говорит, что есть DefaultHttpErrorHandler, что вызывается с исключениями выброшенных из BodyParser.

В документации для ScalaErrorHandling есть примеры настройки или написания собственного.

1

Проблема здесь состоит в том, что вы пытаетесь использовать синхронный обработчик ошибок для обработки асинхронных ошибку. try catch может обрабатывать только синхронные ошибки. Future[_] является асинхронным по своей природе, и он будет, если таковой будет, вызывать ошибку после того, как оператор try catch уже выполнен (и, возможно, в другом потоке).

Вместо этого, в scala, мы делаем обработку ошибок явной, используя структуру данных, такую ​​как Option или Either или \/ от scalaz. Все эти обертки Форма Monad.

В большинстве асинхронных настройки сервера, что вы хотите Future с Either внутри (или правой необъективной вариант как \/ от scalaz.) Таким образом, вы абстрактные над как asynchronity и обработки ошибок. Поскольку обе обертки являются монадами, вы можете комбинировать их с помощью Monad Transformers.Это глубокая тема и требует совсем немного обучения, если вы не знакомы с ним, но суть структуры таких данных будет что-то вроде следующего:

class Task[E, A] { 
    def flatMap[U](f: A => Task[E, U]): Task[E, U] = ??? // Use monad transformer here. 
} 

где E представляет тип пользовательских ошибок - вы, вероятно, будете представлять их через алгебраические типы данных, такие как sealed trait с большим количеством case class и A - это ваш тип значения.

+0

Проблема заключается в том, что 'SomeCustomBodyParser' генерирует исключение, а try/catch не запускается вообще. Независимо от того, выполнялось ли оно асинхронно, это не имеет значения, поскольку оно не выполняется. – colinjwebb

+0

Для записи '' '' Either''' не является монадой в scala. – rethab

 Смежные вопросы

  • Нет связанных вопросов^_^