Akka Http客户端报错:在TypedActor实现方法外调用TypedActor.context
问题描述
我参考示例构建Akka Http客户端时遇到错误,以下是相关代码及报错信息:
客户端实现代码
trait HttpServer { def sendAndReceive: HttpRequest => Future[HttpResponse] } trait ApiHandler extends HttpServer { implicit def as: ActorSystem override def sendAndReceive: HttpRequest => Future[HttpResponse] = Http().singleRequest(_) } trait Api { this: ApiHandler => implicit def as: ActorSystem implicit def mat: Materializer implicit def ec: ExecutionContext def request(httpRequest: HttpRequest): Future[HttpResponse] = { sendAndReceive(httpRequest).flatMap { response => response.status match { case StatusCodes.OK => Future.successful(response) case _ => throw new RuntimeException ("error") } } } } class ApiImpl() (implicit val as: ActorSystem, val mat: Materializer, val ec: ExecutionContext) extends Api with ApiHandler { def request: Future[HttpResponse] = { val httpRequest = ??? request(httpRequest) } }
调用代码
implicit val actorSystem = ActorSystem("system") implicit val executionContext = actorSystem.dispatcher implicit val materializer = ActorMaterializer() val api = new ApiImpl() api.request
错误信息
在Api trait中sendAndReceive(httpRequest).flatMap { response =>这一行,触发如下错误:
Calling TypedActor.context outside of a TypedActor implementation method!
问题分析与修复
错误原因
Http().singleRequest隐式依赖不全:Http().singleRequest需要隐式的ActorSystem、Materializer和ExecutionContext三者才能正常工作,但你的ApiHandlertrait仅声明了ActorSystem,缺失另外两个关键隐式参数,导致Akka内部尝试从错误的上下文(如TypedActor的context)获取依赖,从而抛出异常。ApiImpl存在递归调用问题:ApiImpl中的request方法未构造合法的HttpRequest实例,反而直接调用request(httpRequest),会触发无限递归,即使解决了第一个错误,后续也会出现栈溢出异常。
修复方案
- 给
ApiHandler补充完整的隐式参数:
trait ApiHandler extends HttpServer { implicit def as: ActorSystem implicit def mat: Materializer implicit def ec: ExecutionContext override def sendAndReceive: HttpRequest => Future[HttpResponse] = Http().singleRequest(_) }
- 修正
ApiImpl的递归问题,实现具体请求逻辑:
class ApiImpl() (implicit val as: ActorSystem, val mat: Materializer, val ec: ExecutionContext) extends Api with ApiHandler { // 重命名方法避免与trait中的request冲突,同时构造合法请求 def fetchTargetResource(): Future[HttpResponse] = { val httpRequest = HttpRequest( HttpMethods.GET, uri = "http://your-target-api.com/path" // 替换为实际请求地址 ) request(httpRequest) } }
- 调用修正后的方法:
implicit val actorSystem = ActorSystem("system") implicit val executionContext = actorSystem.dispatcher implicit val materializer = ActorMaterializer() val api = new ApiImpl() api.fetchTargetResource()
内容的提问来源于stack exchange,提问作者Jelly
相关产品推荐
相关产品推荐

