Spray/Akka缺少隐含

mat*_*ter 7 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)
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:当试图直接传递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的答案为编译器留下了歧义的空间......

cfc*_*hou 20

我今天早些时候遇到了"无法找到参数eh:spray.routing.ExceptionHandler的隐含值"错误.我尝试了@Christian的方法,但看到一些"xxx的隐含价值"逐渐上升.在侦察错误消息后,我发现添加implicit val system = context.systemrunRoute解决问题的演员.


Chr*_*ian 2

runRoute 需要一些隐含的内容。您缺少导入:

import spray.routing.RejectionHandler.Default
Run Code Online (Sandbox Code Playgroud)

更新: 我认为我们在 runRoute 方面也遇到了一些问题,因为我们显式提供了隐式参数:

runRoute(route)(ExceptionHandler.default, RejectionHandler.Default, context,
      RoutingSettings.default, LoggingContext.fromActorRefFactory)
Run Code Online (Sandbox Code Playgroud)

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

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)
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)