我如何根据 Future 的结果 return 做出不同的响应?

How do I return different response based on result of Future?

我的登录端点大致如下所示

get {
  (path("token") & parameters("email", "password")) { (email, password) =>
    complete {
      DBManager.getUserByEmail(email) match {
        case Some(user) =>
          // Check everything is return something
          UserWire(user)
        case None => StatusCodes.NotFound -> "User doesn't exist"
      }
    }
  }
}

DBManager.getUserByEmailreturnsOption[User]。我刚刚切换到 Slick,那里的一切都是异步的,因此现在是方法 returns Future[User].

当 future 失败时如何发送所需的响应?我试过这个

    complete {
      DBManager.getUserByEmail(email).map(user => {
        // Check everything is return something
        UserWire(user)
      }).recoverWith { case ex => Future.successful(StatusCodes.NotFound -> "User doesn't exist") }
    }

编译失败

Error:(497, 26) type mismatch;
 found   : scala.concurrent.Future[Product with Serializable]
 required: akka.http.scaladsl.marshalling.ToResponseMarshallable
          }).recoverWith { case ex => Future.successful(StatusCodes.NotFound -> "User doesn't exist") }
                         ^

我该如何解决?

在 spray 中你可以使用 onComplete,它有一个 future 和 returns 一个指令,所以在你的情况下:

onComplete(DBManager.getUserByEmail(email)) {
  case Success(optUser) =>
    complete {optUser.map(UserWire(_)).getOrElse(StatusCodes.NotFound -> "User doesn't exist") }
  case Failure(_) =>
    complete { InternalServerError() }
}

虽然我从未使用过,但 Akka http 似乎有 same method.

第一件事。当您构建反应式应用程序时,最好只对成功的操作进行操作。处理未来的失败比成功的操作需要更多的资源。 DBManager.getUserByEmail 的响应式版本应该 return Future[Option[User]]

当你有未来时,只需将结果映射到可编组形式或响应。

get {
  (path("token") & parameters("email", "password")) { (email, password) =>
    complete {
      DBManager.getUserByEmail(email) map {
        case Some(user) =>
          UserWire(user)
        case None => 
          StatusCodes.NotFound -> "User doesn't exist"
      }
    }
  }
}