遭遇getReader() has already been called for this request错误
该错误的原因是HttpServletRequest的getInputStream()和getReader()只能调用一次,【getReader()底层调用了getInputStream()】。@RequestBody也是流的形式读取,流读取一次就没了。
这种场景一般出现在拦截器中读取了流,并且接口使用了@RequestBody注解的,就会导致重复读取流,抛出这个异常。
解决方法:
因为过滤器是优先于拦截器执行的,所以我们可以写一个过滤器,在过滤器里面把流的数据copy一份出来,放入自定义的Wrapper对象,然后把这个wrapper对象当做request往下传递(wrapper和request可以强转),这样在拦截器中拿到的就是我们copy出来的流,就可以反复读取了,如
过滤器:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request = new AuthRequestWrapper(request);
filterChain.doFilter(request,response);
}
AuthRequestWrapper:
@Slf4j
public class AuthRequestWrapper extends HttpServletRequestWrapper {
private String body;
public AuthRequestWrapper(HttpServletRequest request) {
super(request);
try(BufferedReader reader = request.getReader()){
body= reader.lines().collect(Collectors.joining());
}catch (Exception e){
log.error("!!-- read request from requestbody error",e);
}
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletIns = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return byteArrayIns.read();
}
};
return servletIns;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
后续拦截器使用:
if (request instanceof AuthRequestWrapper){
return ((AuthRequestWrapper)request).getBody();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?