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

集成测试遇ResourceAccessException:请求重定向次数过多解决

问题分析

你遇到的重定向循环问题根源很明确:

  • 你的SecurityConfig强制所有请求必须走HTTPS,而默认的TestRestTemplate会发送HTTP请求到随机分配的端口
  • 服务器收到HTTP请求后返回重定向到HTTPS,但TestRestTemplate默认不处理自签名SSL证书,也没有自动切换到HTTPS端口发起请求,最终导致循环重定向直到达到次数上限
解决方案

以下是几种可以保留SSL配置同时让测试通过的方案,按推荐度排序:

方案一:自定义TestRestTemplate+直接调用HTTPS端口(推荐)

这个方案既保留生产环境的SSL强制逻辑,又能让测试正常执行:

1. 在测试类中添加自定义TestRestTemplate配置

创建一个测试专用的配置类,生成信任自签名证书的TestRestTemplate:

@TestConfiguration
static class TestSslConfig {
    @Bean
    public TestRestTemplate testRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        try {
            // 初始化SSL上下文,信任所有证书(仅测试环境使用)
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                @Override
                public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
            }}, new SecureRandom());

            // 构建忽略证书验证的HttpClient
            HttpClient httpClient = HttpClientBuilder.create()
                    .setSSLContext(sslContext)
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .build();

            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            throw new RuntimeException("SSL配置初始化失败", e);
        }
        return new TestRestTemplate(restTemplate);
    }
}

2. 修改测试方法,直接调用HTTPS端口

通过@LocalServerPort获取Spring Boot随机分配的HTTPS端口,构造HTTPS请求:

@Autowired
TestRestTemplate testRestTemplate;

@LocalServerPort
private int httpsPort;

@Test
void happyPath_findAllUser_integrationTest() {
    String requestUrl = String.format("https://localhost:%d/findAllUser", httpsPort);
    ResponseEntity<UserEntity[]> response = testRestTemplate.getForEntity(requestUrl, UserEntity[].class);
    assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}

方案二:通过Profile区分测试与生产环境

如果不需要在测试环境验证HTTPS强制逻辑,可以通过Spring Profile关闭测试环境的SSL强制:

1. 修改SecurityConfig,添加Profile限制

@Configuration
@Profile("!test") // 仅非test环境生效
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.requiresChannel(channel -> channel.anyRequest().requiresSecure())
                .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll())
                .csrf(csrf -> csrf.disable())
                .formLogin(login -> login.disable())
                .httpBasic(httpBasic -> httpBasic.disable());
        return http.build();
    }
}

2. 在测试类中激活test Profile

@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public class UserServiceIntegrationTest {
    // 原有测试代码不变
}

方案三:配置Spring Boot同时监听HTTP和HTTPS端口

在application.properties中添加HTTP端口配置,让测试用HTTP端口发起请求,服务器自动重定向到HTTPS:

server.port=8443
server.http.port=8080
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=keystorepassword
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=selfsignedcertificate

然后在测试类中获取HTTP端口,发送请求(仍需自定义TestRestTemplate信任证书):

@Autowired
TestRestTemplate testRestTemplate;

@Value("${server.http.port}")
private int httpPort;

@Test
void happyPath_findAllUser_integrationTest() {
    String requestUrl = String.format("http://localhost:%d/findAllUser", httpPort);
    ResponseEntity<UserEntity[]> response = testRestTemplate.getForEntity(requestUrl, UserEntity[].class);
    assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 03:12:10