Spring Boot接口返回User对象超时,转字符串正常问题求助
问题分析与解决方案
核心问题1:直接复用Keycloak返回的ResponseEntity
你当前直接返回RestTemplate从Keycloak获取的ResponseEntity<User>,这个对象包含了Keycloak返回的所有响应头(比如Content-Length、Transfer-Encoding等)。当Spring将这个ResponseEntity转发给Postman时,这些头信息可能和实际序列化后的User对象内容不匹配(比如Content-Length是Keycloak返回的原始JSON长度,而非序列化User对象后的长度),导致Postman一直等待符合长度的内容,最终超时。
而返回字符串时,你通常是自行构建新的ResponseEntity,Spring会自动生成正确的响应头,因此能正常返回。
核心问题2:User类字段拼写错误
User类中acessToken字段拼写错误(正确应为accessToken),虽然@JsonProperty("access_token")能让反序列化正常工作,但序列化时Jackson会基于getter方法生成JSON键(默认是acessToken),既不符合预期的access_token格式,也可能引发潜在的序列化异常(虽不是超时直接原因,但需修正)。
修复代码
1. 修改TokenController,返回自定义ResponseEntity
不再直接返回RestTemplate的ResponseEntity,提取body后构建新的响应:
@RequestMapping("/public/token") @RestController public class TokenController { @Value("${KEYCLOAK_URL}") private String KEYCLOAK_URL; private static final String CLIENT_ID = "my-app"; private static final String GRANTYPE = "password"; @PostMapping public ResponseEntity<User> token(@RequestBody Login login) { HttpHeaders headers = new HttpHeaders(); RestTemplate rt = new RestTemplate(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(); formData.add("client_id", CLIENT_ID); formData.add("username", login.username); formData.add("password", login.password); formData.add("grant_type", GRANTYPE); HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(formData, headers); // 仅获取响应体,而非完整ResponseEntity User user = rt.postForObject(KEYCLOAK_URL + "/protocol/openid-connect/token", entity, User.class); // 构建新的ResponseEntity,由Spring生成正确的响应头 return ResponseEntity.ok(user); } public record Login(String username, String password) {} }
2. 修正User类的字段拼写
@AllArgsConstructor @NoArgsConstructor @Builder @Data public class User { @JsonProperty("access_token") private String accessToken; // 修正拼写错误 @JsonProperty("expires_in") private Long expiresIn; @JsonProperty("refresh_expires_in") private Long refreshExpiresIn; @JsonProperty("refresh_token") private String refreshToken; @JsonProperty("token_type") private String tokenType; }
额外验证步骤
- 添加日志打印User对象内容,确认反序列化是否正确:
User user = rt.postForObject(...); System.out.println("User对象内容:" + user); - 调整Spring Boot日志级别,将
logging.level.org.springframework.web设为DEBUG,捕获序列化相关异常。
内容的提问来源于stack exchange,提问作者Adriano Gomes
相关产品推荐
相关产品推荐

