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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:57:37