如何在请求抵达Controller前用Interceptor修改请求参数?
问题分析与解决
你遇到的核心问题有两个:
- 错误的序列化方式:你用
SerializationUtils.serialize()将MyObject序列化为Java二进制序列化字节流,但@RequestBody期望的是JSON格式的请求体,因此无法解析,最终导致Controller中MyObject为null。 - 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
相关产品推荐
相关产品推荐

