给定 Future,http4s 可以执行不同的状态代码吗?

Can http4s do different status codes given a Future?

我正在使用 http4s,我有一个 Try 可以生成一些 json 响应数据:

case GET -> Root / "something" =>
   getSomethingTry() match {
    case Success(something) => Ok(something)
    case Failure(CustomNotFoundException(reason)) => NotFound(reason)
    case Failure(CustomConflictException()) => Conflict()
   }

这个函数正确returns一个Task[Response]

但是,我想用 Future 替换 Try。匹配不再有效,因为未来可能在匹配时尚未解决。所以,我可以描绘未来:

case GET -> Root / "something" =>
   getSomethingFuture().map {
    something => Ok(something)
   }.recover {
    case CustomNotFoundException(reason) => NotFound(reason)
    case CustomConflictException() => Conflict()
   }

但是这个 returns 一个 Future[Task[Response]] 这不是 http4s 想要的。使用 Await.result 拆箱 Future 似乎不合适 - 我认为这可能会导致线程池问题 - 但它确实使代码工作。

http4s 接受 futures 作为任务创建者的参数:

case GET -> Root / "something" =>
   Ok(getSomethingFuture())

但这并不能让我在出现不同的错误时设置不同的状态码。解决方案可能是对任务执行 .recover,但我看不到明显的方法。

如何在不同的 Future 失败情况下调用不同的 http4s 任务包装器?我需要使用中间件吗?

假设您使用的是 http4s 0.17 及更高版本,您的 Taskfs2.Task

很容易将Future转换为Task,然后处理后者:

case GET -> Root / "something" =>
   Task.fromFuture(getSomethingFuture())
     .flatMap {
       something => Ok(something)
     }
     .handleWith {
       case CustomNotFoundException(reason) => NotFound(reason)
       case CustomConflictException() => Conflict()
     }

不过,我建议在整个程序中使用 Task 而不是 TryFuture

你真的不需要打开未来的包装。 Play 框架提供 action.async 用于返回 Future.

您可以通过以下方式使用

Action.async {
  getSomethingFuture().map {
    something => Ok(something)
   }.recover {
    case CustomNotFoundException(reason) => NotFound(reason)
    case CustomConflictException() => Conflict()
   }
}

https://www.playframework.com/documentation/2.6.x/ScalaAsync#returning-futures