在调用 request.getReader() 后重置 HttpRequest

2022-09-04 08:22:35

有没有办法在 a 上调用该方法,然后“重置”请求,以便其他调用不会抛出?getReader()HttpRequestgetReader()java.lang.IllegalStateException


答案 1

就像其他人说的,不,我认为没有办法重置请求。

在继续之前,我一直处于相同的情况,希望在ServletFilter中记录请求的内容。这是一个论坛帖子,帮助我弄清楚如何创建一个像Stephen C所说的那样。这将存储数据,以便您可以多次调用和。HttpServletRequestWrappergetReader()getInputStream()

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class MyRequestWrapper extends HttpServletRequestWrapper {

    private HttpServletRequest original;
    private byte[] reqBytes;
    private boolean firstTime = true;

    public MyRequestWrapper(HttpServletRequest request) {
        super(request);
        original = request;
    }

    @Override
    public BufferedReader getReader() throws IOException{

        if(firstTime)
            firstTime();

        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(reqBytes));
        return new BufferedReader(isr);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        if(firstTime)
            firstTime();

        ServletInputStream sis = new ServletInputStream() {
            private int i;

            @Override
            public int read() throws IOException {
                byte b;
                if(reqBytes.length > i)
                    b = reqBytes[i++];
                else
                    b = -1;

                return b;
            }
        };

        return sis;
    }

    private void firstTime() throws IOException{
        firstTime = false;
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = original.getReader();
        String line;
        while((line = reader.readLine()) != null){
            buffer.append(line);
        }
        reqBytes = buffer.toString().getBytes();
    }
}

答案 2

简单的答案是“不”。

该流不可重置,并且没有 API 方法允许您重新打开它。(这是有充分理由的。它需要 servlet 基础结构保留输入的副本,以防 servlet 决定重新打开流。这将是一个不必要的开销。

如果你想做这种事情,你需要编写你的代码来保留它自己的数据副本。如果您在过滤器(或Tomcat Valve)中实现此功能,那么您可以创建一个来隐藏您已经读取数据的事实....正如@Vineet所建议的那样。HttpServletRequestWrapper


推荐