【问题标题】:resetting a HttpRequest after calling request.getReader()调用 request.getReader() 后重置 HttpRequest
【发布时间】:2011-06-12 14:24:58
【问题描述】:

有没有办法在HttpRequest 上调用getReader() 方法,然后“重置”请求,这样对getReader() 的其他调用就不会抛出java.lang.IllegalStateException

【问题讨论】:

  • 我对这个问题感到困惑。 API 不允许在同一请求上调用 getInputStream 和 getReader。你想避免这种情况吗?或者您是否试图在同一个请求对象上获得多个读者?
  • @Vineet 我正在尝试提取请求正文并记录它,然后将请求传递给下一个处理程序(在我的情况下为弹簧组件)并让它们照常工作。我想避免你描述的场景。
  • 您是否尝试过使用 HttpServletRequestWrapper? AFAIK,很难(或不可能)在流或读取器对象中重置标记。您可以提取请求,填充包装器对象并将其传递到下游。这纯粹是一个理论概念;您实际上可能必须尝试一下,看看它是否有效。
  • 不,它是 J2EE 对象吗?
  • 是的,它是 Servlet API 的一部分。

标签: java jakarta-ee httprequest


【解决方案1】:

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

在继续之前,我一直希望在 ServletFilter 中记录请求的内容。这是一个forum post,它帮助我弄清楚了如何创建一个HttpServletRequestWrapper,就像 Stephen C 所说的那样。这将存储数据,以便您可以多次调用getReader()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 阀门)中实现此功能,那么您可以创建一个HttpServletRequestWrapper 来隐藏您已经读取数据的事实......正如@Vineet 所建议的那样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-06
    • 2016-05-29
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多