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
相关产品推荐
相关产品推荐

