getReader() has already been called for this request
问题现场:
原因:
HttpServletRequest 的 getInputStream() 和 getReader() 都只能读取一次。
因为 我们使用@RequestBody 注解,读取body参数;而 又 写了拦截器,也需要将post请求,body数据拿出来。
由于@RequestBody 也是流的形式读取,流读了一次就没有了。
解决方案:
过滤器是优先于拦截器的, 我们写一个过滤器,在过滤器里面 把流数据 copy一份出来用,也就是复写一哈。
在拦截器上使用我们复写的流数据就行。
BodyWrapperFilter.java
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;/*** @Author: JCccc* @Date: 2022-6-12 10:35* @Description:*/
public class BodyWrapperFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {ServletRequest requestWrapper = null;if(servletRequest instanceof HttpServletRequest) {requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);}if(requestWrapper == null) {filterChain.doFilter(servletRequest, servletResponse);} else {filterChain.doFilter(requestWrapper, servletResponse);}}
}
CustomHttpServletRequestWrapper.java
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;/*** @Author: JCccc* @Date: 2022-6-12 10:36* @Description: 重写一个自己的 RequestWrapper 拿出body给自己用*/public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {private byte[] body;public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {super(request);BufferedReader reader = request.getReader();try (StringWriter writer = new StringWriter()) {int read;char[] buf = new char[1024 * 8];while ((read = reader.read(buf)) != -1) {writer.write(buf, 0, read);}this.body = writer.getBuffer().toString().getBytes();}}public String getBody(){return new String(body, StandardCharsets.UTF_8);}@Overridepublic ServletInputStream getInputStream() {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() {return byteArrayInputStream.read();}};}@Overridepublic BufferedReader getReader() {return new BufferedReader(new InputStreamReader(this.getInputStream()));}
}
WebApplicationConfig.java
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author: JCccc* @Date: 2022-6-23 10:52* @Description:*/
@Configuration
public class WebApplicationConfig {@BeanBodyWrapperFilter getBodyWrapperFilter(){return new BodyWrapperFilter();}@Bean("bodyWrapperFilter")public FilterRegistrationBean<BodyWrapperFilter> checkUserFilter(BodyWrapperFilter bodyWrapperFilter) {FilterRegistrationBean<BodyWrapperFilter> registrationBean = new FilterRegistrationBean();registrationBean.setFilter(bodyWrapperFilter);registrationBean.addUrlPatterns("/*");registrationBean.setOrder(1);registrationBean.setAsyncSupported(true);return registrationBean;}}
然后就是在拦截器里面,如果我们想取出body,我们改成这样用:
CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request; String nowParams = wrapper.getBody();
效果:
好的,这篇就到这。
getReader() has already been called for this request相关推荐
- getInputStream/getReader() has already been called for this request
getInputStream/getReader() has already been called for this request 一.背景 定义了一个安全校验过滤器,现在要获取请求参数. 通过r ...
- 解决:getReader() has already been called for this request
在 Filter 中对 request 中的 body 进行参数签名校验, 会报如下错误: getReader() has already been called for this request 原 ...
- java getreader_异常处理:getReader() has already been called for this request
场景描述: 在 Spring Boot 自定义拦截器中,需要对请求 body 中的内容做签名验证.在日志切面中,需要打印请求 body 中的内容. 报错内容: java.lang.IllegalSta ...
- 异常:getReader() has already been called for this request
一个流不能读两次异常,这种异常一般出现在框架或者拦截器中读取了request中的流的数据,我们在业务代码中再次读取(如@requestBody),由于流中的数据已经没了,所以第二次读取的时候就会抛出异 ...
- springboot filter and interceptor实战之mdc日志打印
1.1 mdc日志打印全局控制 1.1.1 logback配置 <property name="log.pattern" value="%d{yyyy-MM ...
- java获取GET和POST请求参数
URL和参数列表 一 获取请求方式 request.getMethod(); get和post都可用, 二 获取请求类型 request.getContentType(); get和post都可用,示 ...
- Javaweb复习之HTTPTomcatServelet
1.Web概述 1.1 Web和JavaWeb的概念 Web是全球广域网,也称为万维网(www),能够通过浏览器访问的网站. JavaWeb就是用Java技术来解决相关web互联网领域的技术栈 1.2 ...
- 后端获取URL和参数
一:获取URL 1.Request.getRequestURL 返回的是请求的全部,包括http协议.端口号.servlet名字和映射路径,但不包含请求参数. 结果:http://localhost: ...
- java开发中遇到的问题及解决方法
一.文件路径问题大集合 1.System.getProperty("user.dir") #获取当前项目文件夹在磁盘上的绝对路径(java命令执行的地方) 2.File tm ...
最新文章
- ms speech sdk51 TTS使用
- MySQL基础课堂笔记
- app engine_Google App Engine:在您自己的域中托管应用程序
- java商品列表展示_springMVC入门程序。使用springmvc实现商品列表的展示。
- Angular2 的 View Encapsulation(样式封装)
- 音频编解码G729 PCM
- 视频播放设计测试用例
- 《1818黄金眼》将与bilibili合作:两大快乐源泉要合体了
- 敏捷管理第三章《敏捷理解》
- 2021-09-23记录下wifi调试流程
- Tensorflow2.0版本下如何实现Kronecker积
- C语言int型数据范围
- CCF C³-20@滴滴:智能技术与交通治理 | 报名
- html网页制作—登录及注册页面设计
- bzoj2342还是马拉车
- 各种奇奇怪怪的编码,究竟怎么来的?
- VMware16.2.3+debian11.3.0下载安装
- python小工具:文件批量改名
- 微信小程序 - 页面插入广告(激励式广告)超详细教程
- mfcc概念 参数介绍