我正在创建一个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)
后代码失败。任何帮助表示赞赏。
答案 0 :(得分:0)
我对您的代码进行了以下微小更改,测试通过Akka HTTP 10.0.10和Scala 2.12传递:
http://akka.io
,因为向http://www.premierleague.com
发出GET请求会产生301状态代码。ImplicitSender
特征混合到规范中并更改测试以期望来自客户端的“OK响应”消息。为了进行更有意义的测试,我进行了后两项更改。
以下是成功运行的调整后代码。首先,客户:
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
}
}