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

Spring Boot微服务间WebClient通信:接收方未获取到请求体

问题:Spring Boot微服务间WebClient POST请求体丢失

我有两个注册在Eureka上的Spring Boot微服务,尝试通过HTTP建立通信,使用WebClient从服务A向服务B发送POST请求,代码如下:

WebClient webClient = webClientBuilder.build();
System.out.println(request.getAuthId());
System.out.println(request.getFirstName());

Map<String, String> valueMap = new HashMap<>();
valueMap.put("firstName", request.getFirstName());
valueMap.put("lastName", request.getLastName());
valueMap.put("authId", request.getAuthId());

Mono<MessageResponse> createdUser = webClient.post()
        .uri("http://market-service/market/agrinet/auth/add-user")
        .header("language", locale.getLanguage())
        .header("accept-language",locale.getLanguage().toUpperCase())
        .headers(h -> h.setBearerAuth(jwt.getTokenValue()))
        .contentType(MediaType.APPLICATION_JSON)
        .body(BodyInserters.fromValue(valueMap))
        .retrieve()
        .bodyToMono(MessageResponse.class);

return createdUser.block();

我参考其他方案尝试了Map传参方式,也试过直接通过.bodyValue()发送request对象,但两种方式都无效:请求到达服务B时请求体丢失,不过请求头是正常存在的。我查阅了大量资料,但这是个很标准的场景,却找不到问题所在,请问我遗漏了什么?


排查与解决方向

  • 检查服务B的请求接收注解:服务B必须使用@RequestBody注解来接收JSON格式的请求体,不能用@RequestParam或无注解的参数。示例代码:

    // 用Map接收
    @PostMapping("/market/agrinet/auth/add-user")
    public ResponseEntity<MessageResponse> addUser(
        @RequestBody Map<String, String> requestBody,
        @RequestHeader("language") String language
    ) {
        // 业务逻辑
        return ResponseEntity.ok(new MessageResponse());
    }
    
    // 或用自定义DTO接收(需确保DTO有getter/setter和无参构造器)
    @PostMapping("/market/agrinet/auth/add-user")
    public ResponseEntity<MessageResponse> addUser(
        @RequestBody UserRequest userRequest,
        @RequestHeader("language") String language
    ) {
        // 业务逻辑
        return ResponseEntity.ok(new MessageResponse());
    }
    
  • 验证请求对象的序列化能力:如果直接发送自定义request对象,要确保该对象能被Jackson正常序列化。可以在服务A中先序列化测试:

    ObjectMapper objectMapper = new ObjectMapper();
    try {
        String jsonBody = objectMapper.writeValueAsString(request);
        System.out.println("序列化后的请求体: " + jsonBody);
    } catch (JsonProcessingException e) {
        e.printStackTrace(); // 这里会暴露序列化失败的原因,比如缺少无参构造器、字段无getter
    }
    
  • 排查链路中的拦截器/过滤器:检查服务A、服务B或中间网关是否存在自定义的WebFilter、ClientHttpRequestInterceptor,这类组件如果读取了请求体但未重新写入,会导致下游服务无法获取请求体。比如某些日志过滤器会消费掉DataBuffer,需要确保处理后重新构建请求体。

  • 确认服务发现与请求寻址的正确性:虽然请求头能到达,但可以验证market-service是否正确指向服务B实例。可以通过Eureka控制台查看服务状态,或者在服务A中通过DiscoveryClient获取实例地址后替换硬编码URI测试:

    List<ServiceInstance> instances = discoveryClient.getInstances("market-service");
    if (!instances.isEmpty()) {
        String targetUri = instances.get(0).getUri() + "/market/agrinet/auth/add-user";
        // 使用targetUri构造WebClient请求
    }
    
  • 添加请求日志排查发送端问题:在服务A的WebClient中添加过滤器,打印实际发送的请求体,确认请求体是否正确发出:

    WebClient webClient = webClientBuilder
        .filter((clientRequest, exchangeFunction) -> {
            clientRequest.body().subscribe(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                System.out.println("实际发送的请求体: " + new String(bytes, StandardCharsets.UTF_8));
                // 读取后需释放资源
                DataBufferUtils.release(dataBuffer);
            });
            return exchangeFunction.exchange(clientRequest);
        })
        .build();
    

    如果这里能打印出正确的请求体,说明问题出在服务B的接收环节或中间链路。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 07:33:28