天天看點

getReader() has already been called for this request

問題現場:

getReader() has already been called for this request

原因:

HttpServletRequest 的 getInputStream() 和 getReader() 都隻能讀取一次。

因為 我們使用@RequestBody 注解,讀取body參數;而 又 寫了攔截器,也需要将post請求,body資料拿出來。

由于@RequestBody 也是流的形式讀取,流讀了一次就沒有了。

解決方案:

過濾器是優先于攔截器的, 我們寫一個過濾器,在過濾器裡面 把流資料 copy一份出來用,也就是複寫一哈。

在攔截器上使用我們複寫的流資料就行。

BodyWrapperFilter.java

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


/**
 * @Author: JCccc
 * @Date: 2022-6-12 10:35
 * @Description:
 */
public class BodyWrapperFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest) {
            requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        }
        if(requestWrapper == null) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(requestWrapper, servletResponse);
        }
    }
}      

CustomHttpServletRequestWrapper.java

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;

/**
 * @Author: JCccc
 * @Date: 2022-6-12 10:36
 * @Description:  重寫一個自己的 RequestWrapper 拿出body給自己用
 */

public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;
    public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        BufferedReader reader = request.getReader();
        try (StringWriter writer = new StringWriter()) {
            int read;
            char[] buf = new char[1024 * 8];
            while ((read = reader.read(buf)) != -1) {
                writer.write(buf, 0, read);
            }
            this.body = writer.getBuffer().toString().getBytes();
        }
    }
    public String getBody(){
        return new String(body, StandardCharsets.UTF_8);
    }
    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return 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 byteArrayInputStream.read();
            }
        };
    }
    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
}      

WebApplicationConfig.java

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: JCccc
 * @Date: 2022-6-23 10:52
 * @Description:
 */
@Configuration
public class WebApplicationConfig {

    @Bean
    BodyWrapperFilter getBodyWrapperFilter(){
        return new BodyWrapperFilter();
    }
    @Bean("bodyWrapperFilter")
    public FilterRegistrationBean<BodyWrapperFilter> checkUserFilter(BodyWrapperFilter bodyWrapperFilter) {
        FilterRegistrationBean<BodyWrapperFilter> registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(bodyWrapperFilter);
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(1);
        registrationBean.setAsyncSupported(true);
        return registrationBean;
    }

}      

然後就是在攔截器裡面,如果我們想取出body,我們改成這樣用:

CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;

String nowParams = wrapper.getBody();

效果:

繼續閱讀