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

Spring Boot中基于Header校验API请求Payload版本匹配问题

你的代码没抛出期望的UnrecognizedPropertyException,核心有两个问题:

1. 错误使用Java对象序列化而非JSON序列化

你当前用ObjectOutputStream把payload转成字节数组,这是Java专属的二进制序列化格式,不是JSON。之后用ObjectMapper解析这个二进制流,本质上是在处理非JSON数据,根本走不到正常的JSON反序列化逻辑,自然不会触发未知属性的异常。

正确做法是用ObjectMapper把payload序列化成JSON字符串,再转成输入流供后续反序列化使用。

2. Jackson默认忽略未知属性

Jackson的ObjectMapper默认配置为FAIL_ON_UNKNOWN_PROPERTIES=false,遇到DTO中不存在的属性时会直接忽略,不会抛出异常。必须显式开启该配置,才能让它在遇到未知属性时抛出UnrecognizedPropertyException。

修正后的代码

public <T extends ...> void validateExpectedPayloadVersion(JsonApi<T> payload, String version) throws IOException {
    // 用ObjectMapper将payload序列化为JSON字符串,再转为输入流
    ObjectMapper jsonMapper = new ObjectMapper();
    String payloadJson = jsonMapper.writeValueAsString(payload);
    InputStream is = new ByteArrayInputStream(payloadJson.getBytes(StandardCharsets.UTF_8));

    try (InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
        JsonApi<T> payloadRequest;
        try {
            payloadRequest = unmarshallToVersion(streamReader, version);
        } catch (final UnrecognizedPropertyException e) {
            final String offendingPath = StringUtils.join(
                e.getPath().stream().map(JsonMappingException.Reference::getFieldName)
                    .collect(Collectors.toList()), "."
            );
            throw new InvalidException(offendingPath);
        }
    }
}

private <T extends ...> JsonApi<T> unmarshallToVersion(final InputStreamReader inputStreamReader, final String version) throws IOException {
    final ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
    mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    // 关键配置:开启未知属性报错
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

    switch (version) {
        case "center.1.0":
            return (JsonApi<T>) mapper.readValue(inputStreamReader, new TypeReference<JsonApi<CenterDtoV0>>() {});
        case "center.1.1":
        default:
            return (JsonApi<T>) mapper.readValue(inputStreamReader, new TypeReference<JsonApi<CenterDtoV1>>() {});
    }
}

额外提示

  • 可以把ObjectMapper做成单例,避免重复创建带来的性能损耗。
  • 确保CenterDtoV0和CenterDtoV1字段定义准确:CenterDtoV0包含city字段,CenterDtoV1包含route字段,非版本专属字段保持一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:20:59