Spray / Akka缺少隐含

时间:2014-06-18 11:42:35

标签: scala akka spray

MyService.scala:33: could not find implicit value for parameter eh: spray.routing.ExceptionHandler

我在使用Akka时遇到了“缺少隐式”编译错误,在spray.io代码中,对一个单独的后端服务器进行http调用,作为响应http get的一部分。代码需要导入相当多的Spray和Akka库,所以有点难以确定是否存在导致这种情况的库冲突,我宁愿想出如何在这个和其他情况下逻辑地跟踪这类问题。

在调用runRoute(myRoute)

时遇到缺少的隐式

以下是代码:

import spray.routing._
import akka.actor.Actor
import akka.actor.ActorSystem
import spray.http._
import MediaTypes._
import akka.io.IO
import spray.httpx.RequestBuilding._
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import akka.util.Timeout
import HttpMethods._
import akka.pattern.ask
import akka.event.Logging
import scala.concurrent.duration._


// we don't implement our route structure directly in the service actor because
// we want to be able to test it independently, without having to spin up an actor
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {

  log.info("Starting")

  // the HttpService trait defines only one abstract member, which
  // connects the services environment to the enclosing actor or test
  def actorRefFactory = context

  // this actor only runs our route, but you could add
  // other things here, like request stream processing
  // or timeout handling
  def receive = runRoute(myRoute)
}

// this trait defines our service behavior independently from the service actor
trait MyService extends HttpService {

  implicit val system: ActorSystem = ActorSystem()

  implicit val timeout: Timeout = Timeout(15.seconds)

  import system.dispatcher // implicit execution context

  //val logger = context.actorSelection("/user/logger")
  val logger = actorRefFactory.actorSelection("../logger")

  val myRoute =
  {
    def forward(): String = {
      logger ! Log("forwarding to backend")  
      val response: Future[HttpResponse] =
      (IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse]    
      "<html><body><h1>api response after backend processing</h1></body></html>"
    }

    path("") {
      get {
        respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here
          complete(forward)
        }
      }
    }
  }
}

我想知道解决这个问题的最佳方法是什么,希望能够提供有关如何解决类似问题的洞察力,因为它们在某种程度上并不能直接追踪。

编辑:当试图直接传递implicits,如下面的@ christian的答案,我得到:

MyService.scala:35: ambiguous implicit values: both value context in trait Actor of type => akka.actor.ActorContext and value system in trait MyService of type => akka.actor.ActorSystem match expected type akka.actor.ActorRefFactory
RoutingSettings.default, LoggingContext.fromActorRefFactory) ^

不太确定为什么具体如@ christian的回答为编译器留下了歧义的空间......

2 个答案:

答案 0 :(得分:20)

我遇到了同样的“找不到参数eh:spray.routing.ExceptionHandler的隐含值”错误今天早些时候。我尝试了@Christian的方法,但看到一些“xxx的隐含价值”逐渐上升。在仔细检查错误消息后,我发现implicit val system = context.systemrunRoute解决问题的演员添加了{{1}}。

答案 1 :(得分:2)

runRoute期待一些暗示。您缺少导入:

import spray.routing.RejectionHandler.Default

<强>更新 我认为我们也遇到了runRoute的一些问题,因为我们明确地提供了隐式参数:

runRoute(route)(ExceptionHandler.default, RejectionHandler.Default, context,
      RoutingSettings.default, LoggingContext.fromActorRefFactory)

<强> UPDATE2: 要修复上一个错误,请删除ActorSystem的创建(在MyService中,您从MyServiceActor获取actor系统 - 因此您必须使用自我类型注释)。这编译:

import akka.actor.Actor
import akka.io.IO
import spray.httpx.RequestBuilding._
import spray.http.MediaTypes._
import spray.routing.{RoutingSettings, RejectionHandler, ExceptionHandler, HttpService}
import spray.util.LoggingContext
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import akka.util.Timeout
import HttpMethods._
import akka.pattern.ask
import akka.event.Logging
import scala.concurrent.duration._


// we don't implement our route structure directly in the service actor because
// we want to be able to test it independently, without having to spin up an actor
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {

  log.info("Starting")

  // the HttpService trait defines only one abstract member, which
  // connects the services environment to the enclosing actor or test
  implicit def actorRefFactory = context

  // this actor only runs our route, but you could add
  // other things here, like request stream processing
  // or timeout handling
  def receive = runRoute(myRoute)(ExceptionHandler.default, RejectionHandler.Default, context,
    RoutingSettings.default, LoggingContext.fromActorRefFactory)
}

// this trait defines our service behavior independently from the service actor
trait MyService extends HttpService { this: MyServiceActor =>

  implicit val timeout: Timeout = Timeout(15.seconds)

  implicit val system = context.system

  //val logger = context.actorSelection("/user/logger")
  val logger = actorRefFactory.actorSelection("../logger")

  val myRoute =
  {
    def forward(): String = {
      //logger ! Log("forwarding to backend")
      val response: Future[HttpResponse] =
        (IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse]
      "<html><body><h1>api response after backend processing</h1></body></html>"
    }

    path("") {
      get {
        respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here
          complete(forward)
        }
      }
    }
  }
}