【问题标题】:spray.can.Http$ConnectionException: Premature connection closespray.can.Http$ConnectionException:过早的连接关闭
【发布时间】:2014-11-09 16:56:02
【问题描述】:

在下面的测试中,我尝试模拟超时,然后发送正常请求。但是,我得到 spray.can.Http$ConnectionException: Premature connection close (服务器似乎不支持请求管道)

class SprayCanTest extends ModuleTestKit("/SprayCanTest.conf") with FlatSpecLike with Matchers {

  import system.dispatcher

  var app = Actor.noSender

  protected override def beforeAll(): Unit = {
    super.beforeAll()
    app = system.actorOf(Props(new MockServer))
  }

  override protected def afterAll(): Unit = {
    system.stop(app)
    super.afterAll()
  }


  "response time out" should "work" in {
    val setup = Http.HostConnectorSetup("localhost", 9101, false)

    connect(setup).onComplete {
      case Success(conn) => {
        conn ! HttpRequest(HttpMethods.GET, "/timeout")
      }
    }

    expectMsgPF() {
      case Status.Failure(t) =>
        t shouldBe a[RequestTimeoutException]
    }


  }

  "normal http response" should "work" in {

    //Thread.sleep(5000)
    val setup = Http.HostConnectorSetup("localhost", 9101, false)

    connect(setup).onComplete {
      case Success(conn) => {
        conn ! HttpRequest(HttpMethods.GET, "/hello")
      }
    }

    expectMsgPF() {
      case HttpResponse(status, entity, _, _) =>
        status should be(StatusCodes.OK)
        entity should be(HttpEntity("Helloworld"))
    }
  }

  def connect(setup: HostConnectorSetup)(implicit system: ActorSystem) = {
    // for the actor 'asks'
    import system.dispatcher
    implicit val timeout: Timeout = Timeout(1 second)
    (IO(Http) ? setup) map {
      case Http.HostConnectorInfo(connector, _) => connector
    }
  }

  class MockServer extends Actor {
    //implicit val timeout: Timeout = 1.second
    implicit val system = context.system

    // Register connection service
    IO(Http) ! Http.Bind(self, interface = "localhost", port = 9101)

    def receive: Actor.Receive = {
      case _: Http.Connected => sender ! Http.Register(self)

      case HttpRequest(GET, Uri.Path("/timeout"), _, _, _) => {
        Thread.sleep(3000)
        sender ! HttpResponse(entity = HttpEntity("ok"))
      }

      case HttpRequest(GET, Uri.Path("/hello"), _, _, _) => {
        sender ! HttpResponse(entity = HttpEntity("Helloworld"))
      }
    }
  }


}

和我的测试配置:

spray {
  can {
    client {
      response-chunk-aggregation-limit = 0
      connecting-timeout = 1s
      request-timeout = 1s
    }
    host-connector {
      max-retries = 0
    }
  }
}

我发现在这两种情况下,“conn”对象是相同的。 所以我猜当 RequestTimeoutException 发生时,spray 将 conn 放回池中(默认为 4?),下一个案例将使用相同的 conn 但此时,此 conn 保持活动状态,因此服务器会将其视为分块请求.

如果我在第二种情况下放了一些睡眠,它就会过去。 所以我想我必须在收到 RequestTimeoutException 时关闭 conn 并确保第二种情况使用新的连接,对吧?

我该怎么办?有什么配置吗?

谢谢

里昂

【问题讨论】:

    标签: scala spray


    【解决方案1】:

    您不应该在 Actor(您的 MockServer)内部进行阻塞。当它被阻止时,它无法响应任何消息。您可以将 Thread.sleep 和响应包装在 Future 中。甚至更好:使用Akka Scheduler。请务必将 sender 分配给 val,因为它可能会在您异步响应请求时发生变化。这应该可以解决问题:

    val savedSender = sender()
    context.system.scheduler.scheduleOnce(3 seconds){
      savedSender ! HttpResponse(entity = HttpEntity("ok"))
    }
    

    【讨论】:

    • 啊,我的错,忘了actor的单线程行为:)谢谢指出!
    • 嘿!有一个非常相似的问题,但我没有阻止演员..想知道它是什么:stackoverflow.com/questions/29397293/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 2017-07-22
    • 1970-01-01
    相关资源
    最近更新 更多