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

使用ContainerRequestFilter时合法JSON请求抛出400错误的问题排查

问题排查与解决方案

问题原因

你的过滤器核心问题是请求流只能被读取一次:

  • 在过滤器中,你使用CloseShieldInputStream读取了请求流内容,但读取完成后,流的指针已移动到末尾。
  • 后续JAX-RS框架处理MatchResource的processRequest方法时,需要再次读取请求流来解析AppRequest对象,但此时流已无可读数据,导致解析失败,抛出400 Bad Request错误。
  • CloseShieldInputStream仅能防止流被提前关闭,无法解决流无法重复读取的问题。

修复方案

需要在过滤器中复制请求流内容,确保后续处理能重新读取完整的请求数据。修改后的过滤器代码如下:

@Provider
public class AppFilter implements ContainerRequestFilter {
    private static final Logger LOG = Logger.getLogger(AppFilter.class);

    @Inject
    ObjectMapper objectMapper;
    
    @Override
    public void filter(ContainerRequestContext context) throws IOException {
        InputStream originalStream = context.getEntityStream();
        // 复制请求流内容到字节数组,保留原始数据
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = originalStream.read(buffer)) != -1) {
            baos.write(buffer, 0, bytesRead);
        }
        byte[] requestContent = baos.toByteArray();
        
        // 使用复制的内容进行JSON解析校验
        try (InputStream stream = new ByteArrayInputStream(requestContent)) {
            objectMapper.readValue(stream, AppRequest.class);
        } catch (Exception ex) {
            LOG.error(ExceptionUtils.getRootCauseMessage(ex));
        }
        
        // 将复制后的流重新设置回请求上下文,供后续处理使用
        context.setEntityStream(new ByteArrayInputStream(requestContent));
    }
}

额外说明

  • 该方案通过将请求流内容复制到字节数组,创建可重复读取的ByteArrayInputStream,既完成了JSON解析错误的日志记录,又保证了后续资源方法能正常读取请求数据。
  • 若请求体过大,可考虑使用临时文件存储流内容以避免内存占用过高,常规业务场景下字节数组方式足够高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 13:03:17