【问题标题】:Scala future with akka-httpScala 未来与 akka-http
【发布时间】:2016-08-26 13:25:03
【问题描述】:

我需要用 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)
        }
      }
    }
  }

我需要使用插入的 Route ID 返回结果,并在不让线程等待的情况下执行此操作。 如果尝试

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

它无法编译,因为它不返回值。 我知道如何以肮脏的方式制作它,但我真的想以适当的方式制作。

这种情况应该怎么办?

【问题讨论】:

  • 您可以使用Promise 并将值放入success

标签: scala akka-http


【解决方案1】:

使用onSuccess 处理future 完成时的有效响应,使用handleExceptions 处理future 不成功时。

   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")))
  }

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

处理异常: http://doc.akka.io/docs/akka/2.4.9/scala/http/routing-dsl/exception-handling.html

【讨论】:

    【解决方案2】:

    似乎我找到了最有效的方法。它内置在 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))
          }
      }
    

    【讨论】:

      【解决方案3】:

      您可以映射未​​来,然后完成如下请求。

      val future = Database.saveRoute(route)
      val response = future.map(_.getId).recover(_.getMessage)
      complete(response)
      

      附带说明,为了处理异常,最好有一个 ExceptionHandler 并将其与您的路由一起包装。您可以找到示例here

      【讨论】:

        【解决方案4】:

        您几乎没有选择,我将尝试将最常用的选项用于基于 REST API 的解决方案:

        OnSuccess 当你希望你的期望被expectionHandler 冒泡和处理时使用它

          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:当你想手动处理异常时。尝试包装 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

        【讨论】:

          【解决方案5】:

          这个怎么样,替换:

          Database.saveRoute(route)
          

          与:

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

          【讨论】:

            猜你喜欢
            • 2020-06-05
            • 1970-01-01
            • 2017-10-17
            • 2020-02-07
            • 1970-01-01
            • 2019-12-19
            • 2021-05-13
            • 2017-08-01
            • 1970-01-01
            相关资源
            最近更新 更多