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

如何在请求抵达Controller前用Interceptor修改请求参数?

问题分析与解决

你遇到的核心问题有两个:

  1. 错误的序列化方式:你用SerializationUtils.serialize()将MyObject序列化为Java二进制序列化字节流,但@RequestBody期望的是JSON格式的请求体,因此无法解析,最终导致Controller中MyObject为null。
  2. ServletInputStream实现错误:自定义的ServletInputStream中isFinished()和isReady()始终返回false,Spring无法正确判断流的状态,导致读取请求体失败。

修复步骤

1. 替换序列化方式为JSON序列化

在Interceptor中,将Java序列化改为使用ObjectMapper将对象转为JSON字节数组,保证请求体格式符合@RequestBody的解析要求:

修改Interceptor的preHandle方法:

@Component
public class Interceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        CustomHttpServletRequestWrapper wrapper = new CustomHttpServletRequestWrapper(request);
        ObjectMapper objectMapper = new ObjectMapper();

        // 读取原始请求体并转为MyObject
        MyObject newMyObject = objectMapper.readValue(wrapper.getInputStream(), MyObject.class);
        // 添加默认ID,同时处理ids为null的情况
        List<String> newIdsList = newMyObject.getIds();
        if (newIdsList == null) {
            newIdsList = new ArrayList<>();
        }
        newIdsList.add("123");
        newIdsList.add("1234");
        newMyObject.setIds(newIdsList);

        // 将修改后的对象转为JSON字节数组,替换请求体
        byte[] data = objectMapper.writeValueAsBytes(newMyObject);
        wrapper.setBody(data);

        return super.preHandle(wrapper, response, handler);
    }
}

2. 修复CustomHttpServletRequestWrapper的实现

正确实现ServletInputStream的流状态判断方法,同时重写getReader()方法,避免Spring通过Reader读取请求体时出错:

public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;
    private ByteArrayInputStream byteArrayInputStream;

    public CustomHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        try {
            body = IOUtils.toByteArray(request.getInputStream());
            byteArrayInputStream = new ByteArrayInputStream(body);
        } catch (IOException ex) {
            body = new byte[0];
            byteArrayInputStream = new ByteArrayInputStream(body);
        }
    }

    public void setBody(byte[] body) {
        this.body = body;
        this.byteArrayInputStream = new ByteArrayInputStream(body);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }

            @Override
            public boolean isFinished() {
                // 当流中无可用字节时,标记为已读完
                return byteArrayInputStream.available() == 0;
            }

            @Override
            public boolean isReady() {
                // 流始终处于可读取状态
                return true;
            }

            @Override
            public void setReadListener(ReadListener listener) {
                // 异步读取场景无需实现,留空即可
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        // 基于修改后的请求体创建BufferedReader
        return new BufferedReader(new InputStreamReader(byteArrayInputStream, getCharacterEncoding()));
    }
}

3. 额外注意事项

  • 确保请求的Content-Type为application/json,否则@RequestBody无法正确解析请求体。
  • 处理ids为null的边界情况,避免空指针异常(上述Interceptor代码已覆盖该场景)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:52:03