读取 vert.x http 客户端响应正文时抛出 IllegalStateException

IllegalStateException thrown when reading the vert.x http client response body

当我尝试从 http 客户端响应对象读取正文时出现以下错误。我一直没有得到异常,所以我猜这是与 CompletableFuture 相关的线程问题。知道我做错了什么吗?我用的是vert.x 3.8.1

java.lang.IllegalStateException
    at io.vertx.core.http.impl.HttpClientResponseImpl.checkEnded(HttpClientResponseImpl.java:134)
    at io.vertx.core.http.impl.HttpClientResponseImpl.endHandler(HttpClientResponseImpl.java:153)
    at io.vertx.core.http.impl.HttpClientResponseImpl.bodyHandler(HttpClientResponseImpl.java:193)
    at com.diagnostics.Response.body(Web.kt:116)
    at com.diagnostics.Response.bodyNow(Web.kt:111)
    at com.diagnostics.Response.bodyNow$default(Web.kt:110)
    at com.diagnostics.Main.postVerificationTest(Main.kt:73)
    at com.diagnostics.Main.main(Main.kt:52)
    at com.diagnostics.Main.main(Main.kt)

抛出异常的代码:

val response = client.get(requestUri = "/api/info").get(3, TimeUnit.SECONDS)

val expectedStatus = 200
assertConditionOrExit(pvtLog, response.status == expectedStatus, "response status is ${response.status} expecting $expectedStatus")
val body = response.bodyNow()
assertConditionOrExit(pvtLog, body.isNotEmpty(), "body is empty expecting a non empty value")

http 客户端响应对象是从以下代码创建的:

private fun request(
    method: HttpMethod,
    port: Int,
    host: String,
    requestUri: String
): CompletableFuture<Response> {
    val future = CompletableFuture<Response>()
    httpClient.request(method, port, host, requestUri)
        .exceptionHandler { future.completeExceptionally(it) }
        .handler { resp -> future.complete(Response(resp)) }
        .end()
    return future
}

尸体被取回...

fun bodyNow(timeout: Long = 10, unit: TimeUnit = SECONDS): String {
    return body().get(30000, SECONDS)
}

fun body(): CompletableFuture<String> {
    val future = CompletableFuture<String>()
    resp.bodyHandler { buff -> future.complete(buff.toString())}
    return future
}

body() 函数设置 bodyHandler HttpClientRequest 处理程序在 request() 方法中被调用之后。

所以有可能,当您的主线程继续运行时,事件循环接收内容并将其丢弃。如果内容很小,请求甚至可以在设置 bodyHandler 之前结束。

这就是为什么您只是偶尔看到异常的原因。

如果以后要设置bodyHandler,必须暂停HttpClientResponse:

httpClient.request(method, port, host, requestUri)
    .exceptionHandler { future.completeExceptionally(it) }
    .handler { resp -> 
        resp.pause() // Pause the response
        future.complete(Response(resp))
    }
    .end()

设置bodyHandler后恢复:

resp.bodyHandler { buff -> future.complete(buff.toString())}
resp.resume()