【问题标题】:HttpServletRequest.getParameter losing parameterHttpServletRequest.getParameter 丢失参数
【发布时间】:2015-02-02 03:01:20
【问题描述】:

我很困惑 HttpServletRequest.getParameter 有时会返回 null,而我确实将参数包含在我的请求中。

下面的测试程序:

HelloServlet.java:

public class HelloServlet extends HttpServlet {
    private static Executor logExecutor = Executors.newFixedThreadPool(5);

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        logExecutor.execute(new Task(req));
    }
}

class Task implements Runnable {
    private HttpServletRequest req;

    public Task(HttpServletRequest req) {
        this.req = req;
    }

    @Override
    public void run() {
        System.out.println(String.format("a=%s b=%s c=%s",
                req.getParameter("a"), req.getParameter("b"),
                req.getParameter("c")));
    }
}

将此 servlet 映射到 web.xml 中的 /hello

在 tomcat 或 jetty 中启动 servlet,使用 shell 脚本启动请求:

#/bin/sh

for i in {1..100}
do
        curl -i -X GET "http://localhost:8080/hello?a=a&b=b&c=c"
done

服务器日志显示某些请求中的某些参数可能为空,并且这种情况的发生没有规律的模式。如:

a=a b=b c=c
a=a b=b c=c
a=null b=null c=null
a=null b=null c=null
a=null b=null c=null
a=null b=b c=c
a=null b=null c=c
a=a b=b c=c
a=a b=b c=c
a=a b=b c=c
a=a b=b c=c
a=null b=null c=null
a=a b=b c=c
a=null b=b c=c

我发现原因是我无法为我的 Executor 保存 HttpServletRequest 实例。 所以我想知道原因!为什么我在一个请求中持有 HttpServletRequest 实例的操作可能会影响其他请求。

【问题讨论】:

    标签: java servlets


    【解决方案1】:

    据我所知,我认为一旦完成,您将无法访问请求参数。

    您将HttpServletRequest 传递给Thread。有时它会在请求完成之前执行,有时会稍后执行。因此,有时你得到的参数有时是null。

    避免在doGet 或doPost 之外处理HttpServletRequest。您应该将原始请求中的信息复制到单独的数据结构中以供以后处理。

    例如:

    public class HelloServlet extends HttpServlet {
        private static Executor logExecutor = Executors.newFixedThreadPool(5);
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            String data = String.format("a=%s b=%s c=%s",
                    req.getParameter("a"), req.getParameter("b"),
                    req.getParameter("c"));
            logExecutor.execute(new Task(data));
        }
    }
    
    class Task implements Runnable {
        private String data;
    
        public Task(String data) {
            this.data = data;
        }
    
        @Override
        public void run() {
            System.out.println(data);
        }
    }
    

    编辑:

    从Java Servlet Specification中提取:

    3.11 请求对象的生命周期

    每个请求对象只在servlet的service方法范围内有效,或者在filter的doFilter方法范围内有效, 除非为组件启用了异步处理并且 在请求对象上调用 startAsync 方法。在这种情况下 在发生异步处理的情况下,请求对象保持有效 在 AsyncContext 上调用直到完成。 容器常用 回收请求对象以避免性能开销 请求创建对象。 开发人员必须意识到 维护对 startAsync 没有的请求对象的引用 不推荐在上述范围之外调用,因为它 可能有不确定的结果。

    【讨论】:

    • 我很好奇为什么一个 HttpServletRequest 实例的值可能会受到其他请求的影响。
    • 我并不是说 HttpServletRequest 会受到另一个影响。但是一旦请求完成(响应发送到客户端),应用服务器(tomcat、jetty...)可能会清除它的数据。
    【解决方案2】:

    问题是你在这里重新声明了Task 类中的变量req:

    private HttpServletRequest req;
    
    • 所以你的 req 变量在这里甚至没有被初始化,并且什么都没有 处理 servlet 请求。

    • 另外我看不到你在哪里为请求设置了这些参数,那么你在哪里为请求或 req 变量设置了参数a,b and c?

    【讨论】:

      猜你喜欢
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-22
      • 2020-12-17
      • 2016-08-03
      • 1970-01-01
      相关资源
      最近更新 更多