使用scala akka spray进行非常基本的http服务器测试时出错

Joe*_*oel 4 scala httpserver akka spray

我做了一个非常基本的喷雾测试,使用:

  • 阿卡2.10 2.24
  • Scala 2.10.3
  • 喷雾罐1.3.1
  • sbt 0.13
  • IntelliJ 13

这是我的代码:

val myListener: ActorRef = system.actorOf(Props[TestHttpListener], "httpListener")
IO(Http) ! Http.Bind(myListener, interface = "localhost", port = 8080)
Run Code Online (Sandbox Code Playgroud)

httpListener起反应对Http.ConnectedHttp.Register(self).

我使用sbt来运行我的代码.它失败了AbstractMethodError:

[ERROR] [07/12/2014 18:46:48.364] [default-akka.actor.default-dispatcher-5] [ActorSystem(default)] Uncaught error from thread [default-akka.actor.default-dispatcher-5] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled
java.lang.AbstractMethodError: spray.can.HttpManager.akka$actor$ActorLogging$_setter_$log_$eq(Lakka/event/LoggingAdapter;)V
        at akka.actor.ActorLogging$class.$init$(Actor.scala:335)
        at spray.can.HttpManager.<init>(HttpManager.scala:29)
        at spray.can.HttpExt$$anonfun$1.apply(Http.scala:153)
        at spray.can.HttpExt$$anonfun$1.apply(Http.scala:153)
        at akka.actor.TypedCreatorFunctionConsumer.produce(Props.scala:422)
        at akka.actor.Props.newActor(Props.scala:331)
        at akka.actor.ActorCell.newActor(ActorCell.scala:534)
        at akka.actor.ActorCell.create(ActorCell.scala:560)
        at akka.actor.dungeon.FaultHandling$class.finishCreate(FaultHandling.scala:135)
        at akka.actor.dungeon.FaultHandling$class.faultCreate(FaultHandling.scala:129)
        at akka.actor.ActorCell.faultCreate(ActorCell.scala:338)
        at akka.actor.dungeon.FaultHandling$class.faultRecreate(FaultHandling.scala:58)
        at akka.actor.ActorCell.faultRecreate(ActorCell.scala:338)
        at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:428)
        at akka.actor.ActorCell.systemInvoke(ActorCell.scala:447)
        at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:262)
        at akka.dispatch.Mailbox.run(Mailbox.scala:218)
        at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:385)
        at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
        at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
        at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
        at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Run Code Online (Sandbox Code Playgroud)

Sot*_*jor 5

在Scala世界中,小心版本是非常重要的,因为一切都在快速发展,并且不保证主要版本之间的向后兼容性.

喷雾取决于Akka,此页面包含有关支持的组合的信息.

spray 1.3.1针对Scala 2.10.3和Akka 2.3.0以及Scala 2.11.1和Akka 2.3.2构建.

因此,如果您使用Scala 2.10.3,正确版本的Akka将至少为2.3.0.

而且,我认为你从这个页面跟随的例子不是很好.

首先,它忽略了这样一个事实,即初始化事物的代码IO(Http) ! Http.Bind(...)必须在actor中.接受Http.Bind尝试回复的演员,Http.Bound因为来电者不是演员,你会收到死信.

所以,我建议做这样的事情:

class MyApp extends Actor {

  implicit val system = context.system

  override def receive: Receive = {
    case "start" =>
      val myListener: ActorRef = system.actorOf(Props[TestHttpListener], "httpListener")
      IO(Http) ! Http.Bind(myListener, interface = "localhost", port = 8080)
  }
}
Run Code Online (Sandbox Code Playgroud)

然后从main()您的应用程序的方法,您需要做:

val myApp: ActorRef = system.actorOf(Props[MyApp], "myApp")
myApp ! "start"
Run Code Online (Sandbox Code Playgroud)

另一个从示例中不易理解的事情是,在您的侦听器actor中,您不仅需要处理消息,还需要在每个连接上注册自己:

class TestHttpListener extends Actor {
  def receive = {
    case HttpRequest(HttpMethods.GET, Uri.Path("/ping"), _, _, _) =>
      sender() ! HttpResponse(entity = "PONG")

    case c : Tcp.Connected =>
      sender() ! Http.Register(self)
  }
}
Run Code Online (Sandbox Code Playgroud)