Spring Boot传递用户名密码调用RestTemplate API及RestInterceptor 302错误排查
问题1:Spring Boot中使用RestTemplate传递用户名密码调用API
我整理了两种最常用的实现方式,你可以根据目标API的认证方式来选:
方式1:Basic 认证(适用于API采用HTTP Basic Auth的场景)
如果目标API是基于Basic认证的,你可以给RestTemplate配置一个认证拦截器,让它自动把用户名密码加到请求头里:
import org.springframework.http.HttpHeaders; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.security.crypto.codec.Base64; import org.springframework.web.client.RestTemplate; import java.nio.charset.StandardCharsets; import java.util.Collections; public class RestTemplateConfig { public RestTemplate restTemplateWithBasicAuth(String username, String password) { RestTemplate restTemplate = new RestTemplate(); // 构造Basic Auth的请求头 String auth = username + ":" + password; byte[] encodedAuth = Base64.encode(auth.getBytes(StandardCharsets.UTF_8)); String authHeader = "Basic " + new String(encodedAuth); ClientHttpRequestInterceptor interceptor = (request, body, execution) -> { request.getHeaders().set(HttpHeaders.AUTHORIZATION, authHeader); return execution.execute(request, body); }; restTemplate.setInterceptors(Collections.singletonList(interceptor)); return restTemplate; } }
使用时直接注入这个配置好的RestTemplate,调用API时会自动带上认证头,不用每次手动处理。
方式2:表单参数传递用户名密码(适用于API接收表单登录的场景)
如果目标API是通过表单字段(比如username和password)接收认证信息的,你可以构造表单参数作为请求体:
import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; public class ApiCaller { public void callApiWithFormAuth(String apiUrl, String username, String password) { RestTemplate restTemplate = new RestTemplate(); // 设置请求头为表单类型 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // 构造表单参数 MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("username", username); params.add("password", password); HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); // 发送POST请求(根据API的实际请求方法调整) String response = restTemplate.postForObject(apiUrl, request, String.class); // 后续处理响应逻辑... } }
问题2:解决RestInterceptor调用API时出现302重定向的错误
你遇到的<302,[Location:"/TicketingSystem/Index.html", ...]>是典型的重定向响应,大概率是请求没通过目标服务的认证,被强制重定向到登录页面了。下面是具体的排查和解决步骤:
1. 先检查RestTemplate的自动重定向设置
RestTemplate默认是自动跟随重定向的,但如果重定向后的请求没携带原有的认证信息,就会再次被拦截重定向,甚至陷入循环。你可以先关闭自动重定向,手动处理:
import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; public class RestTemplateConfig { public RestTemplate restTemplateWithoutAutoRedirect() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); // 关闭自动跟随重定向 factory.setFollowRedirects(false); RestTemplate restTemplate = new RestTemplate(factory); // 添加上你的RestInterceptor return restTemplate; } }
关闭后,你可以在拦截器或者调用代码里主动处理302响应:读取Location头,带着认证信息重新请求这个地址。
2. 确保拦截器在重定向请求中也携带认证信息
如果目标服务的重定向需要保持会话或认证状态,你的拦截器必须保证重定向后的请求也带上认证凭证:
- 如果是Basic认证,前面问题1的拦截器已经能做到对所有请求添加Auth头;
- 如果是基于Cookie的会话认证,需要把原请求的Cookie传递到重定向请求中,示例代码如下:
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.HttpRequestWrapper; import java.io.IOException; import java.net.URI; public class AuthInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { // 先执行原请求,获取响应 ClientHttpResponse response = execution.execute(request, body); // 如果是302重定向,处理Cookie传递 if (response.getStatusCode() == HttpStatus.FOUND) { String redirectUrl = response.getHeaders().getFirst(HttpHeaders.LOCATION); if (redirectUrl != null) { // 构造新的请求,带上原请求的Cookie和认证信息 HttpRequest newRequest = new HttpRequestWrapper(request) { @Override public URI getURI() { return URI.create(redirectUrl); } }; // 复制原请求的Cookie到新请求 newRequest.getHeaders().putAll(request.getHeaders()); // 关闭原响应,重新执行请求 response.close(); return execution.execute(newRequest, body); } } return response; } }
3. 排查认证信息是否有效
302到登录页最常见的原因是原请求的认证信息无效或缺失:
- 检查你的RestInterceptor是否正确添加了认证头(比如Basic Auth的头格式是否正确,用户名密码是否正确);
- 如果目标服务是基于Session的,确认第一次请求后是否获取了Session Cookie,并在后续请求(包括重定向)中携带;
- 可以先用Postman手动测试API,传递用户名密码,看看是否会返回302,以此确认是代码问题还是认证信息的问题。
内容的提问来源于stack exchange,提问作者jay




