GET接口带@RequestBody调用异常:服务B调用服务A报请求体缺失
问题根源
- HTTP规范与Spring注解冲突:服务A的接口用
@GetMapping却搭配了@RequestBody,这违背了HTTP设计规范——GET请求语义是获取资源,通常不携带请求体。Postman能调用成功是因为它允许GET请求带请求体(非常规用法),但Spring的RestTemplate.getForObject()严格遵循规范,不会将HttpEntity中的请求体发送出去,导致服务A收到的请求无请求体,触发400错误。 - RestTemplate方法选型错误:
getForObject()是专门用于GET请求的方法,仅支持通过URL路径变量或查询参数传递参数,不支持携带请求体,你构造的HttpEntity在这里完全无效。
两种解决办法
办法一:改用POST请求(推荐)
接口需要传递复杂参数时,POST请求更符合HTTP语义:
- 修改服务A的接口:
@PostMapping(value = "/reservationsCheck") public List<LockerReservations> getReservationsCheck(@RequestBody Map<String, Object> requestMap) { return bookingService.availabilityCheckSizeTime( Size.valueOf((String) requestMap.get("size")), LocalDateTime.parse((CharSequence) requestMap.get("start")), LocalDateTime.parse((CharSequence) requestMap.get("end"))); }
- 修改服务B的调用代码:
将getForObject()替换为postForObject():
String url = "http://localhost:8080/v1/api/"; public List<LockerReservations> getReservationsCheck(Size size, LocalDateTime start, LocalDateTime end) { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); Map<String, Object> sizeTimeMap = new HashMap<>(); sizeTimeMap.put("size", size); sizeTimeMap.put("start", start); sizeTimeMap.put("end", end); HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(sizeTimeMap, httpHeaders); LockerReservations[] result = restTemplate.postForObject(url + "reservationsCheck", httpEntity, LockerReservations[].class); return List.of(result); }
办法二:坚持用GET请求,改用查询参数传递
如果必须使用GET,将参数放到URL查询参数中:
- 修改服务A的接口:
去掉@RequestBody,改用@RequestParam接收参数:
@GetMapping(value = "/reservationsCheck") public List<LockerReservations> getReservationsCheck( @RequestParam("size") String size, @RequestParam("start") String start, @RequestParam("end") String end) { return bookingService.availabilityCheckSizeTime( Size.valueOf(size), LocalDateTime.parse(start), LocalDateTime.parse(end)); }
- 修改服务B的调用代码:
通过getForObject()传递查询参数:
String url = "http://localhost:8080/v1/api/reservationsCheck?size={size}&start={start}&end={end}"; public List<LockerReservations> getReservationsCheck(Size size, LocalDateTime start, LocalDateTime end) { String startStr = start.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); String endStr = end.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); LockerReservations[] result = restTemplate.getForObject(url, LockerReservations[].class, size.name(), startStr, endStr); return List.of(result); }
内容的提问来源于stack exchange,提问作者Kiemoon
相关产品推荐
相关产品推荐

