集成测试遇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
相关产品推荐
相关产品推荐

