SpringBoot/Security重复使用request.getInputStream()

SpringBoot/Security重复使用request.getInputStream()

问题前提:您已经知道该方法得到的ServletInputStream只能读取一次,若后续需要继续使用则会报错Stream Closed。网上的很多方法并不完全可靠,因此本人踩坑后总结本文。

1、构造自定义HttpServletRequestWrapper

核心点:注意返回新的ServletInputStream一定也要重写read(byte b[], int off, int len),该方法是jackson等json工具内部调用的。

若不重写该方法会调用InputStream的该方法默认实现,从而调用您定义的无参read(),因此本方法保证可以使用。

代码:

package com.gx.utils.rabc;

import lombok.extern.slf4j.Slf4j;
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.ByteArrayInputStream;
import java.io.IOException;

/**
 * @author zlj(gx)
 * @date 2023/7/14
 */
//每次刷新ServletInputStream
@Slf4j
public class InputStreamRewriteHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private final byte[] requestBody;

    /**
     * Constructs a request object wrapping the given request.
     *
     * @param request The request to wrap
     * @throws IllegalArgumentException if the request is null
     */
    public InputStreamRewriteHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //request.getInputStream()得到的是请求全部信息,但好像copy只能拷贝请求体的
        requestBody = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() {

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

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

            @Override
            public void setReadListener(ReadListener listener) {

            }

            //禁用该方法
            @Override
            @Deprecated
            public int read() {
                log.error("自定义类被read单个单词");
                return -1;
            }

            @Override
            public int read(byte b[], int off, int len){
                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody);
                return byteArrayInputStream.read(b, off, len);
            }
        };
    }
}

2、修改传参为该类,由于本人使用Security,则在CsrfFilter后新建一个Filter实现该功能。

package com.gx.security.filter;

import com.gx.utils.rabc.InputStreamRewriteHttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

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


/**
 * @author zlj(gx)
 * @date 2023/7/14
 */
@Slf4j
@Component
public class RequestBodyFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.info("RequestBodyFilter have changed object request to InputStreamRewriteHttpServletRequestWrapper");
        filterChain.doFilter(new InputStreamRewriteHttpServletRequestWrapper(request), response);
    }
}

3、Security配置类使用(新加这一行)

.addFilterAfter(requestBodyFilter, CsrfFilter.class)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值