RestTemplate跨服务POST请求异常:Engine无法调用Web服务接口
我有两个服务:运行在http://localhost:8080的Web服务,以及运行在http://localhost:8081的Engine服务。
Web服务向Engine服务发送POST请求的功能完全正常,相关代码如下:
String checkWinUrl = customProperties.getEngineUrl() + "/checkWin"; RestTemplate restTemplate = new RestTemplate(); HttpEntity<GameDto> request = new HttpEntity<>(new GameDto(game)); try { ResponseEntity<CheckWinResult> response = restTemplate.exchange( checkWinUrl, HttpMethod.POST, request, CheckWinResult.class); CheckWinResult checkWinResult = response.getBody(); if (checkWinResult != null && checkWinResult.isWin()) { Set<Move> result = new HashSet<>(); for (MoveDto move : checkWinResult.getWinMoves()) { result.add(Move.builder().color(GomokuColor.GREEN).columnIndex(move.getColumnIndex()).rowIndex(move.getRowIndex()).build()); } return result; } } catch (RestClientException e) { log.error("Error while computing checkWin : " + e.getMessage()); }
Engine服务对应的RestController接口:
@PostMapping("/checkWin") public CheckWinResult checkWin(@RequestBody GameDto game) { return engineService.checkWin(game); }
但当Engine服务向Web服务发送POST请求时,Web服务始终无法接收到请求。Engine端发送请求的代码如下:
String webAppUrl = customProperties.getWebAppUrl() + "/engineMessage"; RestTemplate restTemplate = new RestTemplate(); HttpEntity<String> request = new HttpEntity<>(message.toString()); restTemplate.exchange(webAppUrl, HttpMethod.POST, request, Void.class);
Web服务对应的RestController接口:
@PostMapping("/engineMessage") public void engineMessage(@RequestBody String engineMessage) { JSONObject jsonMessage = new JSONObject(engineMessage); WebSocketMessage webSocketMessage = new WebSocketMessage(); webSocketMessage.setType(MessageType.valueOf(jsonMessage.getString("type"))); webSocketMessage.setContent(jsonMessage.getString("content")); webSocketController.sendMessage(webSocketMessage); }
请问可能是什么原因?
1. 请求头Content-Type不匹配
Web服务的/engineMessage接口接收@RequestBody String,但Engine端发送请求时未指定Content-Type请求头。默认情况下,RestTemplate发送字符串时会设置Content-Type: text/plain,而Spring MVC处理@RequestBody String时,如果内容是JSON格式,可能因期望application/json头导致解析失败,请求被直接拒绝。
解决方法:给HttpEntity添加正确的请求头:
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> request = new HttpEntity<>(message.toString(), headers);
2. 未捕获请求发送异常
Engine端发送请求时没有添加异常捕获逻辑,即使请求发送失败(如连接超时、4xx/5xx错误、路径不存在等),也无法得知具体报错信息,看起来像是请求没到达Web服务。
解决方法:添加异常捕获并打印详细日志:
try { restTemplate.exchange(webAppUrl, HttpMethod.POST, request, Void.class); } catch (RestClientException e) { log.error("Error sending message to Web service: {}", e.getMessage(), e); }
3. Web服务接口配置或路径问题
- 检查
customProperties.getWebAppUrl()的取值是否正确,拼接后的完整URL是否为http://localhost:8080/engineMessage,避免出现多斜杠、少斜杠或端口错误的情况。 - 确认Web服务的
/engineMessage接口所在的Controller类是否添加了@RestController注解,且被Spring正确扫描到。 - 检查Web服务是否存在Spring Security或自定义拦截器,是否拦截了来自
localhost:8081的请求,需要配置放行该接口或允许跨域请求。
4. 消息格式不合法
如果message.toString()输出的不是合法JSON格式,Web服务端执行JSONObject jsonMessage = new JSONObject(engineMessage)时会抛出异常,若未配置全局异常处理器,请求处理失败后不会返回明确错误,容易误以为请求未到达。
排查方法:
- 在Engine端打印
message.toString()的内容,确认是合法JSON。 - 在Web服务的接口中添加日志,验证请求是否到达:
@PostMapping("/engineMessage") public void engineMessage(@RequestBody String engineMessage) { log.info("Received engine message: {}", engineMessage); // 原有业务逻辑... }
5. RestTemplate消息转换器配置问题
Engine端的RestTemplate可能缺少合适的消息转换器,导致发送的请求编码或格式不符合Web服务的预期。
解决方法:显式配置StringHttpMessageConverter:
RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
内容的提问来源于stack exchange,提问作者Valentin Leblanc

