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

Spring WebClient调用微服务时@PATCH局部更新致非更新字段置空问题

问题描述

我有Node.js和Java两个服务,想用PATCH方法仅更新请求体中的单个字段。直接向Node.js服务(http://localhost:8004/products/xxx)发送如下请求体时,只会更新size字段,其余字段保持不变:

{
    "size": 42
}

但调用Java服务(http://localhost:8005/products/xxx),由其转发请求至Node.js服务时,虽更新了size字段,但其余字段均被置为null,结果如下:

Updated product {
  title: null,
  desc: null,
  img: null,
  categories: null,
  size: '42',
  price: null
}

相关代码

Java代码

public Mono<Products> updateProduct(String id, Products editProduct){
    return  webClient
            .patch()
            .uri("/products/{id}", id)
            .body(Mono.just(editProduct), Products.class)
            .retrieve()
            .bodyToMono(Products.class);
}

@PatchMapping("/products/{id}")
@ResponseStatus(code = HttpStatus.OK)
public Mono<Products> updateProduct(@PathVariable("id") String id, @Validated @RequestBody Products editProduct){
    return  basketService.updateProduct(id, editProduct);
}

Node.js代码

router.patch('/:id', async (req, res) => {
  try{
    const productId = req.params.id
    const updates = req.body

    console.log("Updated product", updates)

    const result = await Product.findByIdAndUpdate(productId, updates)
    res.status(200).json(result);
  
  }catch(err) {
    res.status(500).json(err);
  }
})
问题原因及解决办法

原因

Java的@RequestBody会将请求体序列化为完整的Products对象,未传入的字段会被默认赋值为null。当WebClient把这个包含null字段的完整对象发送给Node.js时,Node.js的findByIdAndUpdate默认会用传入的对象覆盖数据库记录——null值会直接把数据库中原有的字段值改成null。

而直接请求Node.js时,请求体只有size字段,所以只会更新该字段,其余字段不受影响。

解决办法

方案1:修改Java端,仅传递非null字段

方法A:用Map接收请求体

修改Java接口方法,用Map<String, Object>代替Products类接收请求体,这样只会保留传入的字段:

@PatchMapping("/products/{id}")
@ResponseStatus(code = HttpStatus.OK)
public Mono<Products> updateProduct(@PathVariable("id") String id, @RequestBody Map<String, Object> editProduct){
    return basketService.updateProduct(id, editProduct);
}

同时调整WebClient的调用逻辑:

public Mono<Products> updateProduct(String id, Map<String, Object> editProduct){
    return webClient
            .patch()
            .uri("/products/{id}", id)
            .body(Mono.just(editProduct), Map.class)
            .retrieve()
            .bodyToMono(Products.class);
}

方法B:给Products类添加Jackson注解忽略null字段

在Products类上添加@JsonInclude注解,让序列化时自动忽略null值:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Products {
    // 类字段、getter/setter方法
}

这样WebClient发送请求时,只会携带非null的字段,和直接请求Node.js的请求体一致。

方案2:修改Node.js端,明确仅更新传入字段

在findByIdAndUpdate中使用$set操作符,确保只更新传入的字段(避免null值覆盖原有数据),同时添加new: true返回更新后的文档:

const result = await Product.findByIdAndUpdate(
  productId, 
  { $set: updates }, 
  { new: true, runValidators: true }
)

注意:这个方案只能治标,如果Java端仍然传递null字段,还是会将对应数据库字段置为null,因此优先推荐修改Java端的方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:57:19