加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何在不升级到Akka HTTP的情况下停止使用路由DSL的Spr

发布时间:2020-12-16 18:19:21 所属栏目:安全 来源:网络整理
导读:我有这条路线: val route = pathPrefix("es") { path("se") { post { entity(as[JsValue]) { t = complete("ok") } } } ~ path("q" / "show") { get { complete(q) } }} 当我尝试绑定它以便停止它时(根据https://doc.akka.io/docs/akka-http/current/routin
我有这条路线:

val route = pathPrefix("es") {
  path("se") {
    post {
      entity(as[JsValue]) {
        t =>
          complete("ok")
      }
    }
  } ~ path("q" / "show") {
    get {
      complete(q)
    }
  }
}

当我尝试绑定它以便停止它时(根据https://doc.akka.io/docs/akka-http/current/routing-dsl/index.html),我得到一个编译错误:

val bindingFuture = Http().bindAndHandle(route,"0.0.0.0",9100)

Error:(54,46) type mismatch; found : spray.routing.Route
(which expands to) spray.routing.RequestContext => Unit required:
akka.stream.scaladsl.Flow[akka.http.scaladsl.model.HttpRequest,akka.http.scaladsl.model.HttpResponse,Any]
val bindingFuture = Http().bindAndHandle(route,“0.0.0.0”,9100)

如何停止HTTP服务器?目前我可以使用以下命令启动HTTP服务器:

startServer("0.0.0.0",port)

但是,我没有看到如何使用startServer函数来停止它.

更新:我无法按照下面的建议从Spray升级到Akka HTTP(管理,不在我的控制范围内).

看看Http().bindAndHandle,它来自akka-http-core_2.11-2.4.11.1.jar.我看到here我需要一个RouteResult将它转换为Flow.但我在akka-http-core_2.11-2.4.11.1.jar中找不到任何RouteResult.

解决方法

正如其他答案已经表明的那样,你正在混淆Spray和Akka HTTP.这两个库是不同的,它们各自的服务器端组件并不意味着在同一个应用程序中共存.如果您无法迁移到取代Spray的Akka HTTP,则从项目中删除Akka HTTP依赖项,并查看 Spray documentation以获取有关停止Spray服务器的信息:

To explicitly stop the server,send an Http.Unbind command to the HttpListener instance (the ActorRef for this instance is available as the sender of the Http.Bound confirmation event from when the server was started).

The listener will reply with an Http.Unbound event after successfully unbinding from the port (or with an Http.CommandFailed in the case of error). At that point no further requests will be accepted by the server.

显然你正在使用SimpleRoutingApp,这是定义startServer方法的地方.此方法不公开获取对HttpListener actor的引用的方法.如引用文档所述,您必须向此actor发送Http.Unbind消息才能停止服务器.

一个想法是定义自己的actor,它可以发送对HttpListener的引用:

import akka.actor._
import spray.can.Http
import spray.routing._

object MyActor {
  case object GetListener
  def props(route: => Route): Props = Props(new MyActor(route))
}

class MyActor(route: => Route) extends HttpServiceActor {
  import MyActor._

  var httpListener: Option[ActorRef] = None

  def routeReceive: Receive = runRoute(route)

  def serverLifecycleReceive: Receive = {
    case b: Http.Bound =>
      println(s"Successfully bound to ${b.localAddress}")
      val listener = sender()
      httpListener = Some(listener)
    case GetListener =>
      httpListener.foreach(sender ! _)
  }

  def receive = routeReceive orElse serverLifecycleReceive
}

然后使用此actor而不是SimpleRoutingApp来启动服务器:

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.Success
import akka.actor._
import akka.io.IO
import akka.pattern.ask
import akka.util.Timeout
import spray.can.Http
import spray.http._
import spray.routing._
import MyActor

object Main extends App {

  implicit val system = ActorSystem()
  import system.dispatcher
  implicit val timeout = Timeout(5.seconds)

  val route = ???

  val handler = system.actorOf(MyActor.props(route),name = "handler")

  IO(Http) ! Http.Bind(handler,interface = "0.0.0.0",port = 9100)

  // run the below code to shut down the server before shutting down the actor system
  (handler ? MyActor.GetListener)
    .flatMap { case actor: ActorRef => (actor ? Http.Unbind) }
    .onComplete {
      case Success(u: Http.Unbound) =>
        println("Unbinding from the port is done.")
        // system.shutdown()
      case _ =>
        println("Unbinding failed.")
    }
}

所有这些都假设您希望在关闭actor系统之前(或不关闭)显式关闭服务器.如果不是这种情况,您当然可以在不明确停止服务器的情况下关闭actor系统.例如,您可以添加一个路径来处理这个路径(下面的代码是从Spray存储库中的sample applications之一改编的):

object Main extends App with SimpleRoutingApp {
  implicit val system = ActorSystem("simple-routing-app")
  import system.dispatcher

  val route = ...
    ~ (post | parameter('method ! "post")) {
      path("stop") {
        complete {
          system.scheduler.scheduleOnce(1.second)(system.shutdown())(system.dispatcher)
          "Shutting down in 1 second..."
        }
      }
    }

  startServer("0.0.0.0",port = 9100) {
    route
  }.onComplete {
    case Success(b) =>
      println(s"Successfully bound to ${b.localAddress}")
    case Failure(ex) =>
      println(ex.getMessage)
      system.shutdown()
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读