一、为什么只能读一次

原因很简单:因为是流。想想看,java中的流也是只能读一次,因为读完之后,position就到末尾了。

二、解决办法

思路:第一次读的时候,把流数据暂存起来。后面需要的时候,直接把暂存的数据返回出去。

实现逻辑:

  1. 自定义一个HttpServletRequestWrapper,覆写getInputStream()和getReader()方法。
  2. 增加一个Filter,在doFilter()中启用自定义的Wrapper
三、代码

1、自定义的Wrapper

  1. import javax.servlet.ReadListener;
  2. import javax.servlet.ServletInputStream;
  3. import javax.servlet.ServletRequest;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletRequestWrapper;
  6. import java.io.BufferedReader;
  7. import java.io.ByteArrayInputStream;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. import java.io.InputStreamReader;
  11. import java.nio.charset.Charset;
  12. public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
  13. private final byte[] body;
  14. public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
  15. super(request);
  16. String sessionStream = getBodyString(request);
  17. body = sessionStream.getBytes(Charset.forName("UTF-8"));
  18. }
  19. private String getBodyString(ServletRequest request) throws IOException {
  20. StringBuilder sb = new StringBuilder();
  21. InputStream ins = request.getInputStream();
  22. try (BufferedReader isr = new BufferedReader(new InputStreamReader(ins, Charset.forName("UTF-8")));) {
  23. String line = "";
  24. while ((line = isr.readLine()) != null) {
  25. sb.append(line);
  26. }
  27. } catch (IOException e) {
  28. throw e;
  29. }
  30. return sb.toString();
  31. }
  32. @Override
  33. public BufferedReader getReader() throws IOException {
  34. return new BufferedReader(new InputStreamReader(getInputStream()));
  35. }
  36. @Override
  37. public ServletInputStream getInputStream() throws IOException {
  38. final ByteArrayInputStream bais = new ByteArrayInputStream(body);
  39. return new ServletInputStream() {
  40. @Override
  41. public int read() throws IOException {
  42. return bais.read();
  43. }
  44. @Override
  45. public boolean isFinished() {
  46. return bais.available() == 0;
  47. }
  48. @Override
  49. public boolean isReady() {
  50. return true;
  51. }
  52. @Override
  53. public void setReadListener(ReadListener readListener) {
  54. }
  55. };
  56. }
  57. }

2、加个Filter来启用wrapper

  1. import javax.servlet.Filter;
  2. import javax.servlet.FilterChain;
  3. import javax.servlet.FilterConfig;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.ServletRequest;
  6. import javax.servlet.ServletResponse;
  7. import javax.servlet.annotation.WebFilter;
  8. import javax.servlet.http.HttpServletRequest;
  9. import java.io.IOException;
  10. // 启用Filter需要在Springboot的启动类加@ServletComponentScan
  11. @WebFilter(filterName = "bodyReaderFilter", urlPatterns = "/*")
  12. public class BodyReaderFilter implements Filter {
  13. @Override
  14. public void init(FilterConfig filterConfig) throws ServletException {
  15. }
  16. @Override
  17. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  18. HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
  19. ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
  20. filterChain.doFilter(requestWrapper, servletResponse);
  21. }
  22. @Override
  23. public void destroy() {
  24. }
  25. }

RequestBody只能读取一次的问题的更多相关文章

  1. 解决SpringMVC拦截器中Request数据只能读取一次的问题

    解决SpringMVC拦截器中Request数据只能读取一次的问题 开发项目中,经常会直接在request中取数据,如Json数据,也经常用到@RequestBody注解,也可以直接通过request ...

  2. 解决HttpServletRequest的输入流只能读取一次的问题

    背景 通常对安全性有要求的接口都会对请求参数做一些签名验证,而我们一般会把验签的逻辑统一放到过滤器或拦截器里,这样就不用每个接口都去重复编写验签的逻辑. 在一个项目中会有很多的接口,而不同的接口可能接 ...

  3. springboot请求体中的流只能读取一次的问题

    场景交代 在springboot中添加拦截器进行权限拦截时,需要获取请求参数进行验证.当参数在url后面时(queryString)获取参数进行验证之后程序正常运行.但是,当请求参数在请求体中的时候, ...

  4. 大白话讲解如何解决HttpServletRequest的请求参数只能读取一次的问题

    大家在开发过程中,可能会遇到对请求参数做下处理的场景,比如读取上送的参数中看调用方上送的系统编号是否是白名单里面的(更多的会用request中获取IP地址判断).需要对请求方上送的参数进行大小写转换或 ...

  5. Servlet的Request.getInputStream()只能读取一次问题

    Servlet的Request.getInputStream()只能读取一次问题 这个星期公司的项目接口进行改造,公司的接口有的采用了WebService的方式,有的使用的是Http协议+Servle ...

  6. httpServletRequest中的流只能读取一次的原因

    首先,我们复习一下InputStream read方法的基础知识, java InputStream read方法内部有一个,postion,标志当前流读取到的位置,每读取一次,位置就会移动一次,如果 ...

  7. Request.getInputStrema只能读取一次的分析过程

    1. 我们先来看一下继承关系HttpServletRequest 接口继承ServletRequest接口 public abstract interface  ServletRequest{ pub ...

  8. request.getInputStream() 流只能读取一次问题

    问题: 一次开发过程中同事在 sptring interceptor 中获取 request body 中值,以对数据的校验和预处理等操作 .导致之后spring 在读取request body 值做 ...

  9. 解决spring http输入流和输出流只能读取一次

    1.需求:给某些请求接口记录日志,记录请求的数据和响应的数据和请求所花费的时间.这里采用非侵入式编程,也业务代码进行解耦.按照spring AOP 的编程思想. 2.编程设计:在spring 拦截器中 ...

随机推荐

  1. Python各种扩展名(py, pyc, pyw, pyo, pyd)区别

    扩展名 在写Python程序时我们常见的扩展名是py, pyc,其实还有其他几种扩展名.下面是几种扩展名的用法. py py就是最基本的源码扩展名 pyw pyw是另一种源码扩展名,跟py唯一的区别是 ...

  2. 18年今日头条笔试第一题题解:球迷(fans)

    其实本题是加强版,原数据是100*100的,老师为了尊重我们的智商加成了3000*3000并进行了字符串处理…… 上原题~ 球迷 [问题描述] 一个球场C的球迷看台可容纳M*N个球迷.官方想统计一共有 ...

  3. nRF51822 配置超过4个的 按键驱动

    最近一个用到超过4个按键驱动,PCA10028 的板子上只有4个,所以SDK9 的pca10028.h 的宏只定义了4 #define BUTTONS_NUMBER 4 但是我要用超过4个的时候,就不 ...

  4. flask + Python3 实现的的API自动化测试平台---- IAPTest接口测试平台,更名:FXTest 接受定制开发(java版开发完毕)

    **背景: 1.平时测试接口,总是现写代码,对测试用例的管理,以及测试报告的管理持久化做的不够,              2.工作中移动端开发和后端开发总是不能并行进行,需要一个mock的依赖来让他 ...

  5. ssm框架中,项目启动过程以及web.xml配置详解

    原文:https://blog.csdn.net/qq_35571554/article/details/82385838 本篇主要在基于SSM的框架,深入讲解web.xml的配置 web.xml   ...

  6. Delphi内存专题

    第一课: Windows 是多任务的操作系统, 一个任务就是一个应用(应用程序).一个应用占一个进程; 在一个进程里面, 又可以运行多个线程(所以就有了很多"多线程编程"的话题). ...

  7. .Net Core NOPI操作word(一)

    NOPI使用方式 1.安装nuget包 即可使用 Install-Package NPOI 一.创建word文档 //创建生成word文档 string path = "D:\\test.d ...

  8. [代码质量] 代码质量管控 -- 复杂度检测 (JavaScript)

    转载自: https://juejin.im/post/59bb8b546fb9a00a4247532e 背景 代码的复杂度是评估一个项目的重要标准之一.较低的复杂度既能减少项目的维护成本,又能避免一 ...

  9. Devops(二):CentOS7(在线)安装Docker

    安装环境:Centos7.5 从 2017 年 3 月开始 docker 在原来的基础上分为两个分支版本: Docker CE 和 Docker EE.1)Docker CE 即社区免费版2)Dock ...

  10. Ingress-nginx 部署使用

    Ingress-nginx 部署使用   一.Ingress 简介 在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的.为了使外部的应用能够访问集群内 ...