当前位置: 首页 > news >正文

解决: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;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;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;@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();

相关文章:

  • Docker-compose和Consul
  • CV计算机视觉每日开源代码Paper with code速览-2023.10.27
  • modelsim仿真报错:vlog-2388 ‘scl‘ already declared in this scope
  • FPGA_状态机工作原理
  • el-table多选表格 实现默认选中 删除选中列表取消勾选等联动效果
  • SHCTF 山河CTF Reverse方向[Week1]全WP 详解
  • Ansible 的脚本 --- playbook 剧本
  • ITSource 分享 第5期【校园信息墙系统】
  • 【数据结构练习题】删除有序数组中的重复项
  • 基于SSM的汽车维修管理系统
  • 图像处理入门 1(Introduction to image processing)
  • Java架构师软件工程全流程
  • 基于单片机16位智能抢答器设计
  • 【vim 学习系列文章 12 -- vimrc 那点事】
  • 安装k8s
  • [Vue CLI 3] 配置解析之 css.extract
  • 【翻译】babel对TC39装饰器草案的实现
  • ComponentOne 2017 V2版本正式发布
  • Fundebug计费标准解释:事件数是如何定义的?
  • Java IO学习笔记一
  • leetcode46 Permutation 排列组合
  • MySQL用户中的%到底包不包括localhost?
  • uni-app项目数字滚动
  • 学习Vue.js的五个小例子
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • ​iOS安全加固方法及实现
  • ​Spring Boot 分片上传文件
  • #{}和${}的区别?
  • #define,static,const,三种常量的区别
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (33)STM32——485实验笔记
  • (第二周)效能测试
  • (二)hibernate配置管理
  • (转)iOS字体
  • (转)视频码率,帧率和分辨率的联系与区别
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • .dwp和.webpart的区别
  • .mysql secret在哪_MySQL如何使用索引
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .NET开发不可不知、不可不用的辅助类(一)
  • /etc/motd and /etc/issue
  • @Autowired注解的实现原理
  • @transaction 提交事务_【读源码】剖析TCCTransaction事务提交实现细节
  • [ IO.File ] FileSystemWatcher
  • [<MySQL优化总结>]
  • [383] 赎金信 js
  • [Angular] 笔记 6:ngStyle
  • [BetterExplained]书写是为了更好的思考(转载)
  • [C# 开发技巧]如何使不符合要求的元素等于离它最近的一个元素
  • [Editor]Unity Editor类常用方法
  • [Excel] vlookup函数
  • [go] 迭代器模式