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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 02:45:40