TestRestTemplate调用返回302状态码与null响应体问题排查
TestRestTemplate调用公开接口返回302 FOUND与null响应体问题排查与解决
问题背景
近期完成JWT认证实现、HTTPS协议配置后,使用TestRestTemplate调用公开接口/api/entity/{id}时,始终返回302 FOUND状态码与null响应体。生产环境中适配自签名证书的Apache HttpClient可正常工作,但测试环境自定义配置TestRestTemplate后问题仍未解决。
核心原因分析
- HTTP到HTTPS的强制重定向:服务端配置HTTPS后,可能存在HTTP请求自动重定向到HTTPS的规则(如Spring Security的
requiresSecure()、Tomcat连接器配置),测试代码中使用http://localhost发起请求会被重定向到https://localhost,而TestRestTemplate默认未正确处理该重定向或自签名证书验证,导致最终返回302响应与null体。 - 测试用HttpClient未适配自签名证书:测试代码中使用
HttpClients.createDefault()创建的HttpClient默认会验证SSL证书,无法识别自签名证书,即使跟随重定向到HTTPS地址也会因证书校验失败返回异常或null。 - TestRestTemplate配置不当:原测试代码中RestTemplate与RestTemplateBuilder的配置逻辑冗余,未正确将自定义HttpClient注入到TestRestTemplate中。
解决方案
1. 改用HTTPS请求地址
将测试中的endpoint从HTTP改为HTTPS,匹配服务端的HTTPS配置:
String endpoint = "https://localhost:" + serverPort + "/api/entity/1";
2. 配置支持自签名证书的TestRestTemplate
参考生产环境的HttpClient配置,简化测试环境的HttpClient,使其信任自签名证书并允许跟随重定向:
import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.test.web.client.TestRestTemplate; import org.springframework.web.client.RestTemplateBuilder; import javax.net.ssl.SSLContext; // 构建信任所有证书的SSL上下文(仅测试环境使用) SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(null, (certificate, authType) -> true) .build(); // 创建支持自签名证书的Socket工厂 SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); // 构建自定义HttpClient CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(socketFactory) .build(); // 创建请求工厂,允许自动跟随重定向 HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); requestFactory.setFollowRedirects(true); // 构建TestRestTemplate TestRestTemplate testRestTemplate = new TestRestTemplate(new RestTemplateBuilder() .requestFactory(() -> requestFactory)); // 发起HTTPS请求 String endpoint = "https://localhost:" + serverPort + "/api/entity/1"; String response = testRestTemplate.getForObject(endpoint, String.class); System.out.println(response);
3. 确保接口确实为公开访问
检查Spring Security配置,确认/api/entity/{id}未被JWT认证拦截:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/entity/{id}").permitAll() // 公开该接口 .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())); // JWT认证配置 return http.build(); }
4. 排查重定向规则
如果仍存在302,可通过打印响应头查看重定向目标:
ResponseEntity<String> responseEntity = testRestTemplate.getForEntity(endpoint, String.class); System.out.println("状态码:" + responseEntity.getStatusCode()); System.out.println("重定向地址:" + responseEntity.getHeaders().getLocation());
确认重定向地址是否为预期的HTTPS地址,若地址异常需调整服务端的重定向配置。
内容的提问来源于stack exchange,提问作者IceMajor
相关产品推荐
相关产品推荐

