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

Android中RestTemplate.postForEntity首次POST请求报400,重试正常

排查RestTemplate首次POST返回400、重试成功的问题

结合你描述的现象和代码,这个问题大概率出在首次请求的请求内容或客户端初始化状态上——毕竟Swagger/Postman都能正常调用,后端逻辑应该没问题。咱们一步步拆解:

可能的核心原因

1. 首次请求时JWT令牌为空或无效

看你的getHttpEntity方法,虽然捕获了获取token的异常,但如果userStorage.getJsonWebToken()返回null,你并没有做任何处理,直接把空token放到请求头里了。后端校验token失败就会返回400,而重试时(定时同步)token已经被正确初始化或刷新,所以请求成功。

2. RestTemplate重复初始化导致序列化异常

你每次调用postServiceData都新建一个RestTemplate,还重复添加MappingJackson2HttpMessageConverter。首次请求时,可能转换器还没完全初始化,导致请求体序列化出错(比如实体转JSON失败),后端解析不了返回400;重试时环境已经稳定,序列化正常。

3. 初始化ResponseEntity时的NullPointerException干扰调试

你一开始用null的HttpStatus初始化chargerServiceResponse,这会导致后续调用toString()时抛出NPE,掩盖了真实的错误信息,让你没法准确判断首次请求的问题。

对应的解决方案

修复令牌校验逻辑

在getHttpEntity里添加token非空校验,避免空token的请求发送:

@NonNull
public static HttpEntity<?> getHttpEntity(List attributes, Context context) {
    HttpHeaders headers = new HttpHeaders();
    try {
        headers.set(ServiceAppConstants.HEADER_ACCEPT, ServiceAppConstants.MEDIATYPE_JSON);
        UserStorage userStorage = new UserStorage(context);
        String token = userStorage.getJsonWebToken();
        // 新增非空校验,避免无效请求
        if (token == null || token.trim().isEmpty()) {
            throw new IllegalStateException("Valid JWT token is required for this request");
        }
        headers.set(ServiceAppConstants.HEADER_SECURITY_TOKEN, token);
        // 打印请求头,方便调试对比
        Log.d("RestService", "Request Token: " + token);
    } catch (Exception ex) {
        Log.e(RestServiceUtils.class.getName(), "Exception occurred while trying to set token to header", ex);
        // 捕获异常后直接抛出,避免发送无效请求
        throw new RuntimeException("Failed to prepare request headers", ex);
    }
    // 打印请求体,对比首次和重试的内容差异
    Log.d("RestService", "Request Body: " + attributes.toString());
    return new HttpEntity<Object>(attributes, headers);
}

单例化RestTemplate

不要每次请求都新建RestTemplate,全局单例化避免重复初始化问题:

// 在你的工具类或Service里定义单例
private static RestTemplate restTemplate;

public static RestTemplate getRestTemplate() {
    if (restTemplate == null) {
        restTemplate = new RestTemplate();
        // 只添加一次转换器,避免重复初始化导致的序列化问题
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    }
    return restTemplate;
}

然后在postServiceData里调用:

// 替换new RestTemplate()
RestTemplate restTemplate = YourUtilsClass.getRestTemplate();

修复ResponseEntity初始化的NPE问题

不要用null状态初始化,改为在请求成功后赋值,异常时处理错误状态:

public ResponseEntity<ArrayList> postServiceData(List<BasicService> attributes) {
    ResponseEntity<ArrayList> chargerServiceResponse = null;
    try {
        RestTemplate restTemplate = YourUtilsClass.getRestTemplate();
        HttpEntity<?> entity = RestServiceUtils.getHttpEntity(attributes, context);
        chargerServiceResponse = restTemplate.postForEntity(url, entity, ArrayList.class);
        SynchronisationStorage synchronisationStorage = new SynchronisationStorage(context);
        synchronisationStorage.updateLastSynchronisationDate();
        loggingStorageDbHelper.logSuccess(R.string.logging_save_send_charger_service_to_backend, 1000);
    } catch (HttpClientErrorException e) {
        // 异常时设置错误状态,方便后续处理
        chargerServiceResponse = new ResponseEntity<>(e.getStatusCode());
        Log.e("RestService", "Request failed with status: " + e.getStatusCode(), e);
    } catch (Exception e) {
        // 捕获其他未知异常
        Log.e("RestService", "Unexpected error occurred", e);
        chargerServiceResponse = new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
    return chargerServiceResponse;
}

额外调试建议

  • 对比首次请求和重试请求的日志(请求头、请求体),看看两者的差异,这是定位问题最直接的方式。
  • 如果怀疑序列化问题,可以手动把attributes转成JSON字符串,用Postman模拟首次请求的JSON内容,看是否返回400。

内容的提问来源于stack exchange,提问作者WeSt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:43:47