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
相关产品推荐
相关产品推荐

