Невозможно правильно обработать ошибки - PullRequest
0 голосов
/ 22 октября 2018

Я нашел причину, по которой мое приложение ведет себя не так, как мне хотелось бы, но я не знаю, как решить проблему.Подводя итог, мое приложение имеет пользовательский обработчик ошибок, который вызывается при возникновении ошибки.Обработчик ошибок отправляет json сообщений.Но в одном случае ошибки запуска приложения (Future не удается) я хочу Redirect пользователя на домашнюю страницу вместо отправки json сообщения. Но этого не происходит, потому что пользовательский обработчик ошибок отправляет сообщение json раньшеЯ могу отправить Redirect от Future recover.

Одной из функций приложения является проверка регистрации.Пользователь нажимает на url, у которого есть токен.При нажатии url вызывается verifyUser Action.Он выполняет некоторые проверки (с использованием запросов к базе данных с использованием Future s) и в зависимости от успеха или неудачи отправляет атрибут Redirect с signup=success или signup=error (здесь не решается вопрос об ошибке, основываясь на том, существует ли что-то в базе данных)или нет).Однако, если Future не удается (я запросил неправильное поле, которое не является частью схемы базы данных), я хочу снова Redirect, но это не работает, так как пользовательский обработчик ошибок вызывается до recover.Как я могу сделать свое приложение Redirect?

val result:Future[Result] = for{tokenOption:Option[UserToken] <- userTokenRepo.findOne(UserTokenKey(UUID.fromString(token)))  //generator 1 - get token from database
                                    userOption:Option[User] <- if (tokenOption.isDefined) userRepo.findOne(tokenOption.get.userKeys) else Future.successful(None) //generator2. found token, look for corresponding user to which the token belongs
                                    modifiedUser:Option[User] <- if (userOption.isDefined) confirmSignupforUser(userOption.get) else Future.successful(None) //generator 3. found user and token. Update profile
                                    deletedToken:Option[UserTokenKey] <- if(modifiedUser.isDefined) userTokenRepo.delete(UserTokenKey(UUID.fromString(token))) else Future.successful(None)
       }
         yield { //check if we have user and token and modified user here. If any is missing, return error else success
           println("db query results tokenOption: "+tokenOption+", userOption: "+userOption+" : modifiedUserOption: "+modifiedUser+", deletedToken: "+deletedToken)
           if(tokenOption.isDefined && userOption.isDefined && modifiedUser.isDefined && deletedToken.isDefined)
              Redirect("http://localhost:9000/home"+";signup=success")//TODOM - pick from config
           else
             /*TODOM - when redirecting with error, can provide additional info why sign up failed*/
             if(tokenOption.isEmpty)
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
           else if(userOption.isEmpty)
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
           else if(modifiedUser.isEmpty)
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
           else //this shouldn't happen. Unexpected
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
         }
       result.recover { case x => {
         println("Future failed in validateUserSession. Recovering. Returning Internal Server Error" + x)
//before this Redirect, the custom error handler sends json response

         Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
        }
       }

Пользовательский обработчик ошибок

class CustomHttpErrorHandler extends HttpErrorHandler {

    def onClientError(request: RequestHeader, statusCode: Int, message: String) = {
      println("client error: request "+request+", statusCode: "+statusCode+", message:"+message)
      Future.successful(
        Status(statusCode)(Json.toJson(JsonResultError(message)))
      )
    }

    def onServerError(request: RequestHeader, exception: Throwable) = {
      println("server error: request: "+request+", exception: "+exception.getMessage)
      Future.successful(
        InternalServerError(Json.toJson(JsonResultError(exception.getMessage)))
      )
    }

}

Я могу проверить isse, когда вижу две отладки (одна из пользовательского обработчика ошибок и другая из восстановления)

server error: request: GET /ws/users/signup/312c9eaf-f27b-43c7-8dac-445a628c3be8, exception: bucket_id is not a column defined in this metadata

Future failed in validateUserSession. Recovering. Returning Internal Server Errorjava.lang.IllegalArgumentException: bucket_id is not a column defined in this metadata

Я мог бы попытаться проверить, основываясь на исключении, полученном в пользовательском обработчике ошибок, но я думаю, что оно слишком универсальное и не может быть хорошим подходом к проектированию.

1 Ответ

0 голосов
/ 22 октября 2018

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

В частности,выражение

userTokenRepo.findOne(UserTokenKey(UUID.fromString(token)))

вычисляется в текущем потоке, поэтому любое исключение в этом коде не будет перехвачено и вызовет обработчик ошибок по умолчанию.

Решение состоит в том, чтобы вычислить это вTry и немедленно обработать ошибку, если она есть.

Вот как это может выглядеть:

for {
  tokenKey <- Future.fromTry(Try(UserTokenKey(UUID.fromString(token))))
  tokenOption <- userTokenRepo.findOne(tokenKey)
  userOption <- tokenOption.fold(Future.successful)(userRepo.findOne(_.userKeys)) //generator2. found token, look for corresponding user to which the token belongs
  modifiedUser <- userOption.fold(Future.successful)(confirmSignupforUser) //generator 3. found user and token. Update profile
  ...

Любое исключение в этом коде приведет к ошибке Future, котораяВаш recover код будет обрабатывать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...