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

GitHub Actions中Spring Boot Rest服务调用失败:JUnit测试连接拒绝

RestTemplate JUnit测试在GitHub Actions中连接被拒绝的问题分析与解决

错误信息

java.lang.RuntimeException: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:0/print/invoice": Connection refused
    at se.winassist.PrintingAppTest.testGetPrintableDocumentEN(PrintingAppTest.java:75)
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:0/print/invoice": Connection refused
    at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:915)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:895)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:790)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:672)
    at se.winassist.PrintingAppTest.testGetPrintableDocumentEN(PrintingAppTest.java:73)

测试代码

@ExtendWith({SpringExtension.class})
@SpringBootTest(classes = {PrintingApp.class},
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PrintingAppTest {
    @LocalServerPort
    int randomServerPort;

    @Test
    public void testGetPrintableDocumentSE() {
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.add("siteId", "123456789");
        RestTemplate restTemplate = new RestTemplate();
        Invoice invoice = Invoice.builder().invoiceNumber(1234).language("SE").build();
        try {
            RequestEntity<Invoice> requestEntity =
                    new RequestEntity<>(invoice,
                            requestHeaders,
                            HttpMethod.POST,
                            new URI(""));
            ResponseEntity<Resource> responseEntity = restTemplate.exchange(
                    "http://localhost:" + randomServerPort + "/print/invoice",
                    HttpMethod.POST,
                    requestEntity,
                    Resource.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

问题原因

  1. 端口注入失败:错误日志显示请求端口为0,说明@LocalServerPort未正确注入随机端口,核心原因是Spring Boot应用在GitHub Actions环境中启动失败,未完成端口分配。
  2. RequestEntity构造不合理:使用空URI构造RequestEntity,可能与exchange方法中指定的完整URL产生解析冲突。
  3. CI环境资源限制:GitHub Actions runner资源有限,应用启动超时,未完成初始化就执行测试,导致端口未就绪。

解决办法

1. 替换为TestRestTemplate(推荐)

Spring Boot提供的TestRestTemplate会自动适配随机端口,无需手动拼接URL,彻底避免端口注入问题:

@ExtendWith({SpringExtension.class})
@SpringBootTest(classes = {PrintingApp.class},
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PrintingAppTest {
    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void testGetPrintableDocumentSE() {
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.add("siteId", "123456789");
        Invoice invoice = Invoice.builder().invoiceNumber(1234).language("SE").build();
        
        HttpEntity<Invoice> requestEntity = new HttpEntity<>(invoice, requestHeaders);
        ResponseEntity<Resource> responseEntity = testRestTemplate.exchange(
                "/print/invoice",
                HttpMethod.POST,
                requestEntity,
                Resource.class);
    }
}

2. 修复RequestEntity构造逻辑

若坚持使用原生RestTemplate,不要用空URI构造RequestEntity,改用HttpEntity传递请求体和头信息:

// 替换原RequestEntity相关代码
HttpEntity<Invoice> requestEntity = new HttpEntity<>(invoice, requestHeaders);
ResponseEntity<Resource> responseEntity = restTemplate.exchange(
        "http://localhost:" + randomServerPort + "/print/invoice",
        HttpMethod.POST,
        requestEntity,
        Resource.class);

3. 排查应用启动问题

  • 查看GitHub Actions流水线的应用启动日志,检查是否存在依赖缺失、配置错误或启动异常。
  • 确保CI环境的JDK版本、依赖库版本与本地完全一致。

4. 增加测试超时时间

修改pom.xml中的maven-surefire-plugin配置,延长测试进程超时时间,给应用足够的启动时间:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <forkedProcessTimeoutInSeconds>300</forkedProcessTimeoutInSeconds>
    </configuration>
</plugin>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:44:50