如何多次读取request.getInputStream()

在gateway里使用Filter过滤器时,有时候需要多次读取request.getInputStream();
如果不作任何处理,只有第一次可以读取到body中的内容;

为了解决多次读取的问题,需要使用到HttpServletRequestWrapper;

包装类代码如下:

package com.demo.gateway.wrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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;

/**
 * HttpServletRequest包装类
 * @author shpan
 * @date 2022-05-31
 */
public class MutilReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private final Logger logger = LoggerFactory.getLogger(MutilReaderHttpServletRequestWrapper.class);

    private final byte[] body;

    /**
     * 构建一个HttpServletRequest包装类
     * 读取request中保存到body属性值
     * @param request
     * @throws IOException
     */
    public MutilReaderHttpServletRequestWrapper (HttpServletRequest request) throws IOException {
        super(request);
        body = InputStreamToByte(request.getInputStream());
    }

    /**
     * 流转 字节数组
     * @param is 流
     * @return 字节数组
     */
    private byte[] InputStreamToByte(InputStream is) {
        byte[] data = null;
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        try {
            byte[] buffer=new byte[1024];
            int ch;
            while ((ch = is.read(buffer)) != -1) {
                byteStream.write(buffer,0,ch);
            }
            data = byteStream.toByteArray();
        } catch (IOException ex) {
            logger.error("InputStreamToByte error:", ex);
        } finally {
            try {
                byteStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    /**
     * 后面请求链需要读取流时根据写出的body重新生成一个新的流
     */
    @Override
    public ServletInputStream getInputStream() {

        final ByteArrayInputStream bais = new ByteArrayInputStream(body);

        return new ServletInputStream() {

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

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

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

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }
}

使用方式:

RequestContext ctx = RequestContext.getCurrentContext();
// 重新包装request,之后用包装后的request处理
HttpServletRequest request = new BodyReaderHttpServletRequestWrapper(ctx.getRequest());
InpustStream inputStream =request.getInputStream();

需要注意的是:如果后续Filter还有用到request,或者需要路由,则需要将request重新赋值给ctx,否则会抛异常;

 // 原request流被取后数据length已经不一致了,需要重新赋值request
 ctx.setRequest(request);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中提到了流程类的getInputStream()方法,而引用进一步说明了这个方法是在java.lang包中可用的。通过调用getInputStream()方法,我们可以获取一个输入流对象,该对象实际上是ServletInputStream的实例,继承自InputStream。 在Java中,getInputStream()方法用于从HTTP请求中获取输入流,以读取请求的主体内容。这个方法通常用于处理来自客户端的POST请求,以读取请求体中的数据。然而,需要注意的是,一旦调用了getInputStream()方法来读取输入流中的数据,就无法再次读取该输入流。这是因为输入流是单向的,只能按顺序读取一次。所以,如果需要多次读取请求体的内容,可以先将其存储到一个变量中,然后再使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Java Process getInputStream()方法与示例](https://blog.csdn.net/cumtv80668/article/details/107798179)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [request.getInputStream()输入流只能读取一次问题](https://blog.csdn.net/qq_16159433/article/details/120922952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值