You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spock框架cleanupSpec()函数中HTTP连接错误:SSL已禁用

在Spock的cleanupSpec()中调用Micronaut HttpClient出现SSL禁用错误的解决办法

相同的HTTPS GET请求在测试用例和cleanup()中能正常执行,但在cleanupSpec()中调用时抛出错误:

Connect Error: Cannot send HTTPS request. SSL is disabled
io.micronaut.http.client.exceptions.HttpClientException: Connect Error: Cannot send HTTPS request. SSL is disabled

看起来Micronaut的HTTP客户端在cleanupSpec()执行前就已经被关闭,导致无法发起HTTPS请求。

测试代码

@MicronautTest
class TestGetSpec extends Specification {

    @Shared
    @Inject
    HttpClient httpClient

    def cleanup() {
        println("TestGETSpec:: Calling cleanup() function")

        def response = httpClient.toBlocking().exchange(
                HttpRequest.GET("https://jsonplaceholder.typicode.com/posts/1").accept(MediaType.APPLICATION_JSON),
                Object
        )
    }

    def cleanupSpec() {
        println("TestGETSpec:: Calling cleanupSpec() function")

        def response = httpClient.toBlocking().exchange(
                HttpRequest.GET("https://jsonplaceholder.typicode.com/posts/1").accept(MediaType.APPLICATION_JSON),
                Object
        )
    }

    def "test HTTP request with ReactorHttpClient"() {
        when:
        def response = httpClient.toBlocking().exchange(
                HttpRequest.GET("https://jsonplaceholder.typicode.com/posts/1").accept(MediaType.APPLICATION_JSON),
                Object
        )

        then:
        response.status.code == 200
    }
}

错误堆栈

Connect Error: Cannot send HTTPS request. SSL is disabled
io.micronaut.http.client.exceptions.HttpClientException: Connect Error: Cannot send HTTPS request. SSL is disabled
    at app//io.micronaut.http.client.netty.ConnectionManager$Pool.onNewConnectionFailure(ConnectionManager.java:986)
    at app//io.micronaut.http.client.netty.PoolResizer.doSomeWork(PoolResizer.java:157)
    at app//io.micronaut.http.client.netty.PoolResizer.dirty(PoolResizer.java:77)
    at app//io.micronaut.http.client.netty.PoolResizer.addPendingRequest(PoolResizer.java:233)
    at app//io.micronaut.http.client.netty.ConnectionManager$Pool.acquire(ConnectionManager.java:965)
    at app//io.micronaut.http.client.netty.ConnectionManager.connect(ConnectionManager.java:430)
    at app//io.micronaut.http.client.netty.DefaultHttpClient.exchangeImpl(DefaultHttpClient.java:1113)
    at app//io.micronaut.http.client.netty.DefaultHttpClient.lambda$exchange$8(DefaultHttpClient.java:811)
    at app//reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:152)
    at app//reactor.core.publisher.FluxSwitchMapNoPrefetch.subscribeOrReturn(FluxSwitchMapNoPrefetch.java:61)
    at app//reactor.core.publisher.Flux.subscribe(Flux.java:8759)
    at app//reactor.core.publisher.Flux.blockFirst(Flux.java:2703)
    at app//io.micronaut.http.client.netty.DefaultHttpClient$1.exchange(DefaultHttpClient.java:547)
    at app//io.micronaut.http.client.BlockingHttpClient.exchange(BlockingHttpClient.java:77)
    at app//io.micronaut.http.client.BlockingHttpClient.exchange(BlockingHttpClient.java:106)
    at app//com.example.TestGetSpec.cleanupSpec(TestGETSpec.groovy:34)

问题原因

Micronaut的测试上下文在所有测试方法执行完毕后,会在cleanupSpec()执行前就开始销毁Bean,包括注入的HttpClient实例。此时客户端的SSL相关资源已经被释放,无法再发起HTTPS请求。

解决办法

1. 手动创建HttpClient实例

在setupSpec()中手动构建HttpClient,自行控制实例生命周期,直到cleanupSpec()执行完毕再关闭:

@MicronautTest
class TestGetSpec extends Specification {

    @Shared
    HttpClient httpClient

    def setupSpec() {
        httpClient = HttpClient.create(new URL("https://jsonplaceholder.typicode.com"))
    }

    def cleanup() {
        println("TestGETSpec:: Calling cleanup() function")
        def response = httpClient.toBlocking().exchange(
                HttpRequest.GET("/posts/1").accept(MediaType.APPLICATION_JSON),
                Object
        )
    }

    def cleanupSpec() {
        println("TestGETSpec:: Calling cleanupSpec() function")
        def response = httpClient.toBlocking().exchange(
                HttpRequest.GET("/posts/1").accept(MediaType.APPLICATION_JSON),
                Object
        )
        // 手动关闭客户端
        httpClient.close()
    }

    def "test HTTP request with ReactorHttpClient"() {
        when:
        def response = httpClient.toBlocking().exchange(
                HttpRequest.GET("/posts/1").accept(MediaType.APPLICATION_JSON),
                Object
        )

        then:
        response.status.code == 200
    }
}

2. 延迟测试上下文销毁(临时方案)

如果必须使用注入的客户端,可以通过配置让Micronaut延迟销毁上下文,但可能导致资源泄漏,需谨慎使用:
在application-test.yml中添加:

micronaut:
  test:
    context:
      shutdown:
        phase: AFTER_ALL_TEST_METHODS

3. 调整清理逻辑位置

如果cleanupSpec()中的请求并非必须,考虑将逻辑移到cleanup()中;如果是清理远程资源,可改用独立于测试上下文的HTTP客户端(如原生Java HttpClient)执行。

内容的提问来源于stack exchange,提问作者MathProblem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:12:33