一、为什么只能读一次

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

二、解决办法

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

实现逻辑:

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

1、自定义的Wrapper

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset; public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String sessionStream = getBodyString(request);
body = sessionStream.getBytes(Charset.forName("UTF-8"));
} private String getBodyString(ServletRequest request) throws IOException {
StringBuilder sb = new StringBuilder();
InputStream ins = request.getInputStream(); try (BufferedReader isr = new BufferedReader(new InputStreamReader(ins, Charset.forName("UTF-8")));) {
String line = "";
while ((line = isr.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
throw e;
}
return sb.toString();
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
} @Override
public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override
public int read() throws IOException {
return bais.read();
} @Override
public boolean isFinished() {
return bais.available() == 0;
} @Override
public boolean isReady() {
return true;
} @Override
public void setReadListener(ReadListener readListener) {
}
};
}
}

2、加个Filter来启用wrapper

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; // 启用Filter需要在Springboot的启动类加@ServletComponentScan
@WebFilter(filterName = "bodyReaderFilter", urlPatterns = "/*")
public class BodyReaderFilter implements Filter { @Override
public void init(FilterConfig filterConfig) throws ServletException {
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
} @Override
public void destroy() {
} }

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. c++ 获取字符串中最长的回文子串

    #include <vector> #include <iostream> #include <string> using namespace std; strin ...

  2. win7企业版激活

    win7企业版激活:(亲测有效) 打开命令提示符,依次执行下面的代码,分别表示:安装win7企业版密钥,设置kms服务器,激活win7企业版,查询激活期限,kms一般是180天,到期后再次激活. sl ...

  3. manjaro arm在rock pi4b中的配置记录:

    首先说明下我的硬件情况,网上买了: 主要有emmc的转接板,主要是写入emmc镜像使用,32G的emmc,打算安装个android用来看电子书够了.需要自备读卡器,资料太少了,么有说明,考虑了1个多小 ...

  4. Redis主从搭建环境

    一.环境准备 软件环境 redis版本: redis-4.0 操作系统:Centos-7.5 IP:192.168.1.190(主redis) 192.168.1.191(从redis) 硬件环境 服 ...

  5. durpal安装时The translation server is offline解决

    从https://localize.drupal.org/download下载语言文件上传到 目录/var/www/html/sites/default/files/translations 或者wg ...

  6. 新版本Mariadb安装后相关问题的解决

    给新机器Ubuntu安装的Mariadb后无法登录,通过网上各种方法修改root用户密码,仍然无法解决,耗费几个小时! 经过看日志和查手册,发现原因如下: ubuntu确实安装没有启用root用户,所 ...

  7. ubuntu之路——day14 只用python的numpy在底层实现多层神经网络

    首先感谢这位博主整理的Andrew Ng的deeplearning.ai的相关作业:https://blog.csdn.net/u013733326/article/details/79827273 ...

  8. tomcat启动慢的解决办法

    SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generatio ...

  9. https://www.cnblogs.com/LBSer/p/3310455.html

    https://www.cnblogs.com/LBSer/p/3310455.html

  10. 【LeetCode算法-28/35】Implement strStr()/Search Insert Position

    LeetCode第28题 Return the index of the first occurrence of needle in haystack, or -1 if needle is not ...