Scala未来与akka-http

4

我需要使用akka-http和reactivemongo编写简单的Web服务。

保存数据的函数如下:

 def saveRoute(route: Route):Future[WriteResult] = {
    collection.insert(route)
 }

一个调用这个函数的代码看起来像这样:
val userRoutes = {
    logRequestResult("akka-http-microservice") {
      path("routes") {
        (post & entity(as[Route])) { route =>
          Database.saveRoute(route)
        }
      }
    }
  }

我需要返回插入路由ID的结果,并且不需要让线程等待。如果尝试

Database.saveRoute(route).onComplete{
            case Success(r) => complete(r.toString)
            case Failure(e) => complete(e.getMessage)
          }

不能编译,因为它没有返回值。我知道怎么用不规范的方式解决,但真正想以适当的方式解决。

在这种情况下应该怎么办?


你可以使用 Promise 并将值放入 success - sebszyller
6个回答

9

看起来我已经找到了最有效的方法来完成这个任务。它内置于onComplete指令中。

(path("routes" / "add") & post & entity(as[Route])) {
    route =>
      onComplete(routesController.addRoute(route)) {
        case Success(result) => complete(StatusCodes.Created, "OK")
        case Failure(ex) => complete(new ErrorResponse(StatusCodes.InternalServerError.intValue, ErrorResponse.ERROR, ex.getMessage))
      }
  }

6

使用onSuccess处理未来完成时的有效响应,使用handleExceptions处理未来不成功的情况。

   val userRoutes = {
    handleExceptions(mongoDbExceptionHandler) {
      logRequestResult("akka-http-microservice") {
        path("routes") {
          (post & entity(as[Route])) { route =>
            onSuccess(Database.saveRoute(route)) { result =>
              complete(result)
            }
          }
        }
      }
    }
  }

  // Something like this for whatever the exceptions you expect are
  val mongoDbExceptionHandler = ExceptionHandler {
    case ex: MongoDbReadException => complete(HttpResponse(InternalServerError, "No database")))
  }

onSuccess: http://doc.akka.io/docs/akka/2.4.9/scala/http/routing-dsl/directives/future-directives/onSuccess.html

handleExceptions: http://doc.akka.io/docs/akka/2.4.9/scala/http/routing-dsl/exception-handling.html


1
你可以对未来进行映射,然后按照以下方式完成请求。
val future = Database.saveRoute(route)
val response = future.map(_.getId).recover(_.getMessage)
complete(response)

顺便提一下,处理异常时,最好有一个ExceptionHandler并将其与您的路由包装在一起。您可以在这里找到示例here


1
你有几个选项,我会尝试列出最常用的REST API解决方案:
使用OnSuccess当您希望您的期望被冒泡并由异常处理程序处理时。
  concat(
    path("success") {
      onSuccess(Future { "Ok" }) { extraction =>
        complete(extraction)
      }
    },
    path("failure") {
      onSuccess(Future.failed[String](TestException)) { extraction =>
        complete(extraction)
      }
    }
  )

https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/future-directives/onSuccess.html

onComplete:当您想手动处理异常时。请使用Try Monad封装。

val route =
  path("divide" / IntNumber / IntNumber) { (a, b) =>
    onComplete(divide(a, b)) {
      case Success(value) => complete(s"The result was $value")
      case Failure(ex)    => complete((InternalServerError, s"An error occurred: ${ex.getMessage}"))
    }
  }

https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/future-directives/onComplete.html


0

当您使用RequestContext时,应该像这样使用:

import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.RouteResult.{Complete, Rejected}
...
  val myRoute: Route = (path("my-path") & get) { req: RequestContext =>
    val futureResp: Future[HttpResponse] = ???
    futureResp.map(resp => RouteResult.Complete(resp))
  }

0

这样怎么样,替换为:

Database.saveRoute(route)

使用:

complete(Database.saveRoute(route).map(_.toString).recover(_.getMessage))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接