用于GET请求抛出的akka​​-http客户端无法找到本地变量实例

时间:2017-09-20 17:16:49

标签: akka akka-http

我正在创建一个Akka HTTP客户端来发出GET和POST请求。我在文档中使用基于Future的示例。我收到一个错误,上面写着"找不到本地变量实例。"这是一个简单的代码和测试用例。

package com.epl.akka
import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpMethods, HttpRequest, HttpResponse, StatusCodes}
import akka.stream.{ActorMaterializer, ActorMaterializerSettings}
import akka.util.ByteString
import com.epl.akka.AkkaHTTPClient.GET

class AkkaHTTPClient() extends Actor
  with ActorLogging {

  import akka.pattern.pipe
  import context.dispatcher

  final implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system))

  val http = Http(context.system)

  override def receive: Receive = {
    case GET(uri: String) =>
      log.info("getting the url")
      http
        .singleRequest(HttpRequest(HttpMethods.GET,uri = uri))
        .pipeTo(self)

    case HttpResponse(StatusCodes.OK, headers, entity, _) =>
      entity.dataBytes.runFold(ByteString(""))(_ ++ _).foreach { body =>
        log.info("Got response, body: " + body.utf8String)
      }

    case resp @ HttpResponse(code, _, _, _) =>
      log.info("Request failed, response code: " + code)
      resp.discardEntityBytes()
  }  
}

object AkkaHTTPClient {

  def props() =
    Props[AkkaHTTPClient]

  final case class GET(uri: String){}  
}

代码执行的操作是抓取URL并返回HTML响应,然后由JSoup解析以创建JSON结果。

测试用例:

class AkkaHTTPClientSpec(_system: ActorSystem)
  extends TestKit(_system)
  with Matchers
  with FlatSpecLike
  with BeforeAndAfterAll {

  def this() = this(ActorSystem("AkkaHTTPClientSpec"))

  override def afterAll: Unit = {
    shutdown(system)
  }

  "A AkkaHttpClient Actor" should "give HTML response when instructed to" in {
    val testProbe = TestProbe()

    val url = "http://www.premierleague.com"
    val akkaHTTPClientActor = system.actorOf(AkkaHTTPClient.props(),"AkkaHttpClient")
    akkaHTTPClientActor ! GET(url)
  }
}

调用val http = Http(context.system)后代码失败。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

我对您的代码进行了以下微小更改,测试通过Akka HTTP 10.0.10和Scala 2.12传递:

  1. 将网址更改为http://akka.io,因为向http://www.premierleague.com发出GET请求会产生301状态代码。
  2. 更改了客户端代码,向原始发件人发送“确定响应”消息。
  3. ImplicitSender特征混合到规范中并更改测试以期望来自客户端的“OK响应”消息。
  4. 为了进行更有意义的测试,我进行了后两项更改。

    以下是成功运行的调整后代码。首先,客户:

    package com.epl.akka
    
    import akka.actor._
    import akka.http.scaladsl.Http
    import akka.http.scaladsl.model._
    import akka.stream.{ActorMaterializer, ActorMaterializerSettings}
    import akka.util.ByteString
    
    import com.epl.akka.AkkaHTTPClient.GET
    
    class AkkaHTTPClient() extends Actor with ActorLogging {
      import akka.pattern.pipe
      import context.dispatcher
    
      final implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system))
    
      val http = Http(context.system)
    
      var originalSender: Option[ActorRef] = None // <-- added
    
      override def receive: Receive = {
        case GET(uri: String) =>
          val s = sender             // <-- added
          originalSender = Option(s) // <-- added
          log.info("getting the url")
          http
            .singleRequest(HttpRequest(HttpMethods.GET,uri = uri))
            .pipeTo(self)
    
        case HttpResponse(StatusCodes.OK, headers, entity, _) =>
          entity.dataBytes.runFold(ByteString(""))(_ ++ _).foreach { body =>
            log.info("Got response, body: " + body.utf8String)
          }
          originalSender.foreach(_ ! "OK response") // <-- added
    
        case resp @ HttpResponse(code, _, _, _) =>
          log.info("Request failed, response code: " + code)
          resp.discardEntityBytes()
      }
    }
    
    object AkkaHTTPClient {
      def props() = Props[AkkaHTTPClient]
      final case class GET(uri: String)
    }
    

    规范:

    package com.epl.akka
    
    import akka.actor.{Actor, ActorSystem}
    import akka.testkit.{ImplicitSender, TestKit}
    
    import com.epl.akka.AkkaHTTPClient.GET
    import org.scalatest.{BeforeAndAfterAll, FlatSpecLike, Matchers}
    
    import scala.concurrent.duration._
    
    class AkkaHTTPClientSpec(_system: ActorSystem)
      extends TestKit(_system)
      with ImplicitSender  // <-- added
      with Matchers
      with FlatSpecLike
      with BeforeAndAfterAll {
    
      def this() = this(ActorSystem("AkkaHTTPClientSpec"))
    
      override def afterAll: Unit = {
        shutdown(system)
      }
    
      "An AkkaHTTPClient Actor" should "give HTML response when instructed to" in {
        val url = "http://akka.io" // <-- changed
        val akkaHTTPClientActor = system.actorOf(AkkaHTTPClient.props(), "AkkaHttpClient")
        akkaHTTPClientActor ! GET(url)
        expectMsg(20.seconds, "OK response") // <-- added
      }
    }