首页 > 编程语言 >java拦截器获取POST请求体后Controller异常Required request body is missing OR Stream closed

java拦截器获取POST请求体后Controller异常Required request body is missing OR Stream closed

时间:2023-07-14 18:44:49浏览次数:33  
标签:body 拦截器 java request return Override import public

解决办法参考文档:https://blog.csdn.net/qierkang/article/details/88544691

springboot拦截器获取POST请求体后导致Controller中@RequestBody参数异常Required request body is missing OR Stream closed.

1.为什么会报这个错?

因为http的body只能读取一次。

2.为什么body设计为只能读取一次?

A.由于我们获取POST请求参数的时候,是通过读取request的IO流来实现的,一旦读取了那么流关闭后,后续就用不了了。

B.假如别人上传1T的文件,然后Java先全部读取到内存,服务器直接就挂了……所以不确定最大能多大的东西,默认都是流式处理,要缓存反复读。

解决办法:

1.写一个可重复读的Request包装类

import org.springframework.http.HttpMethod;
import org.springframework.util.StreamUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

/**
 * 可重复读的Request包装类
 */
@Slf4j
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {

    /**
     * 缓存下来的HTTP body
     */
    private byte[] body;

    public RepeatedlyRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }

    /**
     * 重新包装输入流
     *
     * @return
     * @throws IOException
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
        InputStream bodyStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return bodyStream.read();
            }

            /**
             * 下面的方法一般情况下不会被使用,如果你引入了一些需要使用ServletInputStream的外部组件,可以重点关注一下。
             * @return
             */
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        InputStream bodyStream = new ByteArrayInputStream(body);
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    
}

2.添加处理可重复读request的过滤器(过滤器记得开启生效)

import com.kuailaimi.security.client.util.RepeatedlyRequestWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 处理可重复读request的过滤器
 */
public class RepeatedlyReadFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //将request可重复读的包装类传递下去
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            requestWrapper = new RepeatedlyRequestWrapper(httpServletRequest);
        }

        if (null == requestWrapper) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }


    @Override
    public void destroy() {
    }
}

3.在拦截器中使用

 if (request instanceof RepeatedlyRequestWrapper) {
     RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
     String body = new String(StreamUtils.copyToByteArray(repeatedlyRequest.getInputStream()), repeatedlyRequest.getCharacterEncoding());
}

 

标签:body,拦截器,java,request,return,Override,import,public
From: https://www.cnblogs.com/runwithraining/p/17554745.html

相关文章

  • Java入门13(socket)
    Socket编程(网络通信)服务器端Demo(ServreSocket)​ 创建服务端时,如果不提供IP地址,则默认为本地连接(127.0.0.1),但是一定需要手动配置监听端口!publicstaticvoidmain(String[]args){//如果不提供IP地址,默认localhost//但是服务器端的端口号需要手动指令try(Serv......
  • java--String类的常用方法
    一、获取1、length()  获取字符串长度Stringstr="ahcckmvevawe";System.out.println(str.length());//输出122、charAt(intindex)  返回下标对应的字符Stringstr="ahcckmvevawe";System.out.println(str.charAt(4));//输出k3、indexOf()  返回字符对......
  • JavaWeb基础:安装tomcat和maven
    JavaWeb基础:安装tomcat和maventomcat闪退问题下载zip即可,无需配置,只需运行相关文件即可文档所在位置:D:\Environment\apache-tomcat-9.0.78\bin开启:startup.bat关闭:shutdown.batjava8不适用tamcat10及以上版本解决办法:https://blog.csdn.net/egegerhn/article/details/1260......
  • java 跨域
       ......
  • JavaScript at() 方法
    数组对象:对于获取数组的最后一个元素,可能平常见得多的就是arr[arr.length-1],我们其实可以使用at()方法进行获取接收一个整数值并返回该索引对应的元素:constarr=[5,12,8,130,44];letindex1=2;strt1=`索引号为${index1}的值为${arr.at(index1)}`;letind......
  • 学习Java第2天
    ##快捷键Ctrl+c复制Ctrl+v粘贴Ctrl+z撤销Ctrl+a全选Ctrl+x剪切Ctrl+s保存Alt+f4关闭窗口Windows+e我的电脑Windows+r运行窗口Ctrl+shift+ESC任务管理器#打开CMD的方式1.开始+系统+命令提示符2.win健+r输入cmd打开控制台(推荐使用)3.在任意的文件夹......
  • 【javascript】关于文件下载
    通常在a标签href属性后加上请求下载文件的地址,页面点击即可下载,该种方式是交由浏览器去下载,但是无法监听下载进度若通过AJAX请求,则需要对其进行解析,通常将数据转为blob,然后模拟a标签点击事件,但是此方法如果文件过大,接口调用时超出ajax的timeout时长,会下载失败......
  • 【JavaScript】你真的熟悉bind吗
    引言内容速递看了本文您能了解到的知识!在本篇文章中,将带你了解什么是bind,bind的用途、如何手写bind以及工作中实际使用bind的场景。在JavaScript中,bind()方法是用来创建一个新函数,并将其绑定到指定的对象上,从而在调用该函数时确保函数中的this关键字指向绑定的对象。1、什......
  • 【JavaScript】js 处理复制函数实现
    exportconstcopyText=(text:string)=>{constinput=document.createElement('input');input.setAttribute('readonly','readonly');input.setAttribute('value',text);document.body.appendChild(input);......
  • java匿名类怎么把数据传递给全局变量
    ThreadLocal:参考:https://blog.csdn.net/u010746364/article/details/50607236/ https://blog.csdn.net/yuanchangliang/article/details/107747545>>Swing组件之间怎么传值?......