getInputStream has already been called for this request 问题记录

这篇具有很好参考价值的文章主要介绍了getInputStream has already been called for this request 问题记录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题背景

HttpServletRequest.getReader()
HttpServletRequest.getInputStream() 不能在过滤器中读取一次二进制流(字符流),又在另外一个Servlet中读取一次,即一个InputSteam(BufferedReader)对象在被读取完成后,将无法再次被读取。二进制流被读取后,字节流/字符流的下标将发生变化,假如程序中重新调用一遍getReader/getInputStream 将会提示异常
getInputStream has already been called for this request 问题记录,java,java

解决方案

思路很简单,既然HttpServletRequest的请求体无法通过getReader/getInputStream再次调用,那我们只需要包装一层,通过Wrapper对象去集成HttpServletRequest的所有能力,并将请求体抽离出来,这样每次读取我们定义的请求体,问题就解决了。这个方法非常灵活。

画个流程图给大家解释下
getInputStream has already been called for this request 问题记录,java,java

通过上述流程图,可以得到关键的两个信息
1、定义包装类HttpServletRequestWrapper
2、全局过滤器filter,把HttpServletRequest包装成

ps:幸好的是,java语言设计者也考虑到了这种场景,已经帮我们准备好Wrapper类,直接集成使用即可。
getInputStream has already been called for this request 问题记录,java,java

代码示例

包装类定义(RepeatedlyReadRequestWrapper.java)

package com.whale.finance.filter;

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

/**
 * @author yanyq
 * @desc 重复读取HttpServletRequest reader/inputstream
 * @date 2023/7/27
 */
public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {

    private final String body;

    /**
     *
     * @param request
     */
    public RepeatedlyReadRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        StringBuilder sb = new StringBuilder();
        InputStream ins = request.getInputStream();
        BufferedReader isr = null;
        try{
            if(ins != null){
                isr = new BufferedReader(new InputStreamReader(ins));
                char[] charBuffer = new char[128];
                int readCount;
                while((readCount = isr.read(charBuffer)) != -1){
                    sb.append(charBuffer,0,readCount);
                }
            }
        }catch (IOException e){
            throw e;
        }finally {
            if(isr != null) {
                isr.close();
            }
        }

        sb.toString();
        body = sb.toString();
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletIns = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

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

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() {
                return byteArrayIns.read();
            }
        };
        return  servletIns;
    }
}

过滤器定义(ReadBodyHttpServletFilter.java)

package com.whale.finance.filter;

import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author yanyq
 * @desc 重复读取HttpServletRequest reader/inputstream
 * @date 2023/7/27
 */
@Component
@WebFilter("/*")
public class ReadBodyHttpServletFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        RepeatedlyReadRequestWrapper requestWrapper = new RepeatedlyReadRequestWrapper(httpServletRequest);
        filterChain.doFilter(requestWrapper, httpServletResponse);
    }

    @Override
    public void destroy() {
    }
}

进行验证测试

    /**
     * 测试request.getReader
     */
    @PostMapping("/list")
    public void test(HttpServletRequest request) {
        request.getReader(); // 不报错
        return;
    }

Reference
https://blog.csdn.net/feeltouch/article/details/103275416文章来源地址https://www.toymoban.com/news/detail-612305.html

到了这里,关于getInputStream has already been called for this request 问题记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [ This request has no response data available问题 ]

    目录 前言: 提示背景: 问题导致情况: 跨域设置: Canceled    摸鱼来了  接口响应200 response返回提示:This request has no response data available 1: 确定是否是跨域引起, 一般情如果有跨域会报跨域错误。报无响应的比较少。 2: 浏览器端的代码问题了,然后发现问题请求的代码执行后,紧

    2024年02月15日
    浏览(58)
  • [AI使用问题记录] ClaudeAI“您的账户在…”被停用后,如何解决?(Claude3:This organization has been disabled.)

    自动审查导致停用 存在使用限制 Claude账号因自动审查导致停用,以及存在使用限制问题。 自动审查风险 频繁切换IP访问会导致账号被封禁。 使用接码平台的账户同样存在被直接封禁的风险。 跨国登录账号也可能受到停用限制。 使用限制问题 停用情形 停用原因 账号注册异

    2024年04月09日
    浏览(35)
  • SurfaceView出现ANR:Surface has already been released的解决办法

    项目中有这样一种场景会引起SurfaceView出现ANR,在主Activity中创建并使用SurfaceView,然后不停的进入子ActivityB ,返回主Activity再进入子ActivityB这样循环,就会出现ANR的问题。 我通过查看SurfaceView源码发现了一个坑,其实很多人使用的姿势不对,他们没有出现ANR只是幸运而已。

    2024年02月01日
    浏览(40)
  • Cannot Reference “XxxClass.xxx” Before Supertype Constructor Has Been Called

    百度翻译:在调用超类型构造函数之前无法引用“XxxClass.xxx” ----- 我的理解:在一个类的构造器方法还未执行的时候,我们无法使用这个类的成员属性或成员方法。   下面是会出现此错误的示例代码 IDE提示错误: Cannot reference \\\'MyException.getErrorCode\\\' before supertype constructor has

    2024年02月09日
    浏览(33)
  • Cannot Reference “XxxClass.xxxmember” Before Supertype Constructor Has Been Called

    百度翻译:在调用超类型构造函数之前无法引用“XxxClass.xxx” ----- 我的理解:在一个类的构造器方法还未执行的时候,我们无法使用这个类的成员属性或成员方法。   下面是会出现此错误的示例代码 IDE提示错误: Cannot reference \\\'MyException.getErrorCode\\\' before supertype constructor has

    2024年02月09日
    浏览(34)
  • 报错解决:Cannot call sendError() after the response has been committed

    报错背景:   在做开源项目《瑞吉外卖》时,编写拦截器代码后,前端登录时,后端报错如下:            思考与思路:          Cannot call sendError() after the response has been committed.....意思是,当response已经提交后,不能再sendError()。那也就是说,我在代码中一定是

    2024年02月11日
    浏览(43)
  • IDEA之This license XXXX has been suspended

    IDEA激活码突然报如下错误: 解决方案: IDEA版本2022.2.3,亲测管用

    2024年04月10日
    浏览(44)
  • 解决java.lang.IllegalStateException: Cannot call sendError() after the response has been committed异常

    相信大家自己在用spring boot写restful风格的接口时特别是写文件下载或文件导出时会碰到java.lang.IllegalStateException: Cannot call sendError() after the response has been committed这样的bug,很多人可能一脸困惑,就好奇为什么我文件都已经可以正常导出了,为什么在日志中还是会出现这样的报错

    2024年02月16日
    浏览(44)
  • java.lang.IllegalStateException: Illegal access: this web application instance has been stopped

    java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already.  Could not load [org.apache.logging.log4j.core.impl.Log4jLogEvent$Builder]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access. 部署web项目出现在这个问题,其

    2024年02月16日
    浏览(36)
  • 【报错】:Module path has been externalized for browser...

    Vite2+Vue3下引入path模块报错:Module “path” has been externalized for brower compatibility and cannot be accesed in client code 原因是 vite 源码中设定了不允许在客户端代码中访问内置模块代码。 1,安装 npm install path-browserify 2,使用 path-browserify 代替 path 模块 3,不再使用 import path from \\\'path\\\' ,改

    2024年02月12日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包