如何多次读取request.getInputStream()

该博客介绍了一个在网关中使用Filter时如何处理HttpServletRequest的包装类,以便能够多次读取请求体。MutilReaderHttpServletRequestWrapper类通过缓存请求体内容,实现了ServletInputStream的重写,使得在过滤链中可以多次访问输入流。文章还提醒注意在后续Filter或路由处理中需要正确地重新赋值request,以避免异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值