问题现场:

原因:

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相关推荐

  1. getInputStream/getReader() has already been called for this request

    getInputStream/getReader() has already been called for this request 一.背景 定义了一个安全校验过滤器,现在要获取请求参数. 通过r ...

  2. 解决:getReader() has already been called for this request

    在 Filter 中对 request 中的 body 进行参数签名校验, 会报如下错误: getReader() has already been called for this request 原 ...

  3. java getreader_异常处理:getReader() has already been called for this request

    场景描述: 在 Spring Boot 自定义拦截器中,需要对请求 body 中的内容做签名验证.在日志切面中,需要打印请求 body 中的内容. 报错内容: java.lang.IllegalSta ...

  4. 异常:getReader() has already been called for this request

    一个流不能读两次异常,这种异常一般出现在框架或者拦截器中读取了request中的流的数据,我们在业务代码中再次读取(如@requestBody),由于流中的数据已经没了,所以第二次读取的时候就会抛出异 ...

  5. springboot filter and interceptor实战之mdc日志打印

    1.1  mdc日志打印全局控制 1.1.1    logback配置 <property name="log.pattern" value="%d{yyyy-MM ...

  6. java获取GET和POST请求参数

    URL和参数列表 一 获取请求方式 request.getMethod(); get和post都可用, 二 获取请求类型 request.getContentType(); get和post都可用,示 ...

  7. Javaweb复习之HTTPTomcatServelet

    1.Web概述 1.1 Web和JavaWeb的概念 Web是全球广域网,也称为万维网(www),能够通过浏览器访问的网站. JavaWeb就是用Java技术来解决相关web互联网领域的技术栈 1.2 ...

  8. 后端获取URL和参数

    一:获取URL 1.Request.getRequestURL 返回的是请求的全部,包括http协议.端口号.servlet名字和映射路径,但不包含请求参数. 结果:http://localhost: ...

  9. java开发中遇到的问题及解决方法

    一.文件路径问题大集合 1.System.getProperty("user.dir")    #获取当前项目文件夹在磁盘上的绝对路径(java命令执行的地方) 2.File tm ...

最新文章

  1. ms speech sdk51 TTS使用
  2. MySQL基础课堂笔记
  3. app engine_Google App Engine:在您自己的域中托管应用程序
  4. java商品列表展示_springMVC入门程序。使用springmvc实现商品列表的展示。
  5. Angular2 的 View Encapsulation(样式封装)
  6. 音频编解码G729 PCM
  7. 视频播放设计测试用例
  8. 《1818黄金眼》将与bilibili合作:两大快乐源泉要合体了
  9. 敏捷管理第三章《敏捷理解》
  10. 2021-09-23记录下wifi调试流程
  11. Tensorflow2.0版本下如何实现Kronecker积
  12. C语言int型数据范围
  13. CCF C³-20@滴滴:智能技术与交通治理 | 报名
  14. html网页制作—登录及注册页面设计
  15. bzoj2342还是马拉车
  16. 各种奇奇怪怪的编码,究竟怎么来的?
  17. VMware16.2.3+debian11.3.0下载安装
  18. python小工具:文件批量改名
  19. 微信小程序 - 页面插入广告(激励式广告)超详细教程
  20. mfcc概念 参数介绍

热门文章

  1. 一个2层隐层神经网络解决抑或问题
  2. 帮我写一段能实时获取经纬度和具体地区的python代码
  3. 中级软考-软件设计师(三)
  4. java 大数据处理之内存溢出解决办法
  5. python里有哪些函数_python update函数会调用哪些内置函数_Python函数之内置函数
  6. 【echarts记录 -- 3d 饼状图实现】
  7. 一文带你透析zookeeper原理
  8. 如何绘制公司组织结构图
  9. 数学建模16(阻滞增长模型、BP神经网络)
  10. 华为p50官方首曝鸿蒙,华为P50,会是鸿蒙系统的首发手机吗?