【问题标题】:Can I turn off the HttpSession in web.xml?我可以关闭 web.xml 中的 HttpSession 吗?
【发布时间】:2011-01-16 09:10:59
【问题描述】:

我想完全消除 HttpSession - 我可以在 web.xml 中执行此操作吗?我确信有特定于容器的方法可以做到这一点(当我进行 Google 搜索时,这会挤满搜索结果)。

附:这是一个坏主意吗?在我真正需要它们之前,我更喜欢完全禁用它们。

【问题讨论】:

  • 多么有趣的问题。我有一种情况,使用 Tomcat,没有为我创建会话,所以我正在寻找是否有办法在 web.xml 中打开会话 on。 :D

标签: java session web-applications web.xml


【解决方案1】:

我想完全消除 HttpSession - 我可以在 web.xml 中执行此操作吗?我确信有容器特定的方法可以做到这一点

我不这么认为。禁用HttpSession 将违反Servlet 规范,该规范规定HttpServletRequest#getSession 应返回会话或创建会话。所以我不希望 Java EE 容器提供这样的配置选项(这会使其不兼容)。

这是个坏主意吗?在我真正需要它们之前,我更喜欢完全禁用它们。

好吧,我真的不明白这一点,如果您不想使用它,请不要在会话中添加任何内容。现在,如果您真的想阻止会话的使用,您可以使用Filter 将请求替换为覆盖getSession()HttpServletRequestWrapper 实现。但我不会浪费时间来实现这个:)

更新:我最初的建议不是最佳的,“正确”(咳嗽)的方法是替换请求。

【讨论】:

    【解决方案2】:

    您可以使用 URL 重写过滤器(例如 tuckey rewrite filter)重写 URL,而不是禁用。这将为 Google 提供友好的结果,但仍允许基于 cookie 的会话处理。

    但是,您可能应该为所有响应禁用它,因为它比搜索引擎不友好更糟糕。它公开了可用于certain security exploits 的会话ID。

    Example config 用于 Tuckey 过滤器:

    <outbound-rule encodefirst="true">
      <name>Strip URL Session ID's</name>
      <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
      <to>$1$2$3</to>
    </outbound-rule>
    

    【讨论】:

      【解决方案3】:

      我想彻底消除 HttpSession

      您不能完全禁用它。您需要做的只是通过request.getSession()request.getSession(true) 在您的Web 应用程序代码中的任何位置处理它,并确保您的JSP 不会通过设置隐式执行此操作&lt;%@page session="false"%&gt;.

      如果您真正关心的是禁用在 HttpSession 幕后使用的 cookie,那么您可以在 Java EE 5 / Servlet 2.5 中仅在特定于服务器的 webapp 配置中这样做。例如在 Tomcat 中,您可以在 &lt;Context&gt; 元素中将 cookies 属性设置为 false

      <Context cookies="false">
      

      另见Tomcat specific documentation。这样,会话将不会保留在未重写 URL 的后续请求中——仅当您出于某种原因从请求中获取它时。毕竟,如果你不需要它,只是不要抓住它,那么它根本不会被创建/保留。

      或者,如果您已经在使用 Java EE 6 / Servlet 3.0 或更新版本,并且真的想通过 web.xml 来实现,那么您可以使用 web.xml 中的新 &lt;cookie-config&gt; 元素,如下所示归零-超出最大年龄:

      <session-config>
          <session-timeout>1</session-timeout>
          <cookie-config>
              <max-age>0</max-age>
          </cookie-config>
      </session-config>
      

      如果您想在您的网络应用程序中进行硬编码,以便 getSession() 永远不会返回 HttpSession(或“空”HttpSession),那么您需要创建一个过滤器来监听 url-pattern 的 @ 987654339@ 将HttpServletRequest 替换为HttpServletRequestWrapper 实现,该实现返回所有getSession() 方法null,或者一个虚拟的自定义HttpSession 实现什么都不做,甚至抛出UnsupportedOperationException

      @Override
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
          chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
              @Override
              public HttpSession getSession() {
                  return null;
              }
              @Override
              public HttpSession getSession(boolean create) {
                  return null;
              }
          }, response);
      }
      

      附注这是一个坏主意吗?在我真正需要它们之前,我更喜欢完全禁用它们。

      如果您不需要它们,请不要使用它们。就这样。真的:)

      【讨论】:

      • HttpServletRequestWrapper 听起来不错,我会同意的。在有许多开发人员的大型项目中,您需要强制执行架构决策(例如无状态)。你不能依赖人们“根本不使用它”。
      • “如果你不需要它们,就不要使用它们” 没那么简单。您的项目使用的数百个库中的一些可能会在某处创建会话。
      • @David:那么就质疑相关库吗?
      • @Balus 所以没有应用程序服务器可以在不创建 HttpSession 并将数据存储至少一分钟的情况下处理请求?对吗?
      • 很遗憾看到 Java EE 根本不是为无状态、无会话应用程序设计的,这是构建可扩展 Web 应用程序的最佳现代技术之一。这也是出现 express.js 和 Play 框架等新技术的原因。默认情况下它们是无状态的,并且它们确实是非常可扩展的服务器端框架,可以轻松地在单个常规机器上同时为数千人提供服务。我建议将它们用于新项目。
      【解决方案4】:

      对于 RESTful 应用程序,我只是在每次请求的生命周期结束时使其无效。无论您是否调用request.getSession(),都可能有一些Web 服务器在新客户端访问时总是创建新会话。

      【讨论】:

        【解决方案5】:

        我对我的 RESTful 应用程序使用以下方法来删除任何无意的会话 cookie,以免被创建使用。

        <session-config>
            <session-timeout>1</session-timeout>
            <cookie-config>
                <max-age>0</max-age>
            </cookie-config>
        </session-config>
        

        但是,这并没有完全关闭 HttpSessions。应用程序仍可能无意中创建了会话,即使它在一分钟内消失并且流氓客户端也可能忽略 cookie 的 max-age 请求。

        这种方法的优点是您不需要更改您的应用程序,只需web.xml。我建议您创建一个HttpSessionListener,它会记录会话的创建或销毁时间,以便您跟踪它何时发生。

        【讨论】:

          【解决方案6】:

          无法避免会话创建。但是您可以在请求周期结束时检查您是否违反了自己的要求。因此,创建一个简单的 servlet 过滤器,将其放置在 chain.doFilter 之后,如果创建了会话,则会抛出异常:

          chain.doFilter(request, response);
          if(request.getSession(false) != null)
              throw new RuntimeException("Somewhere request.getSession() was called");
          

          【讨论】:

            【解决方案7】:

            如果您正在构建无状态的高负载应用程序,您可以像这样禁用 cookie 进行会话跟踪(非侵入性,可能与容器无关):

            <session-config>
                <tracking-mode>URL</tracking-mode>
            </session-config>
            

            要强制执行此架构决策,请编写如下代码:

            public class PreventSessionListener implements HttpSessionListener {
            @Override
            public void sessionCreated(HttpSessionEvent se) {
                throw new IllegalStateException("Session use is forbidden");
            }
            
            @Override
            public void sessionDestroyed(HttpSessionEvent se) {
                throw new IllegalStateException("Session use is forbidden");
            }
            }
            

            并将其添加到 web.xml 并修复因该异常而失败的地方:

            <listener>
                <listener-class>com.ideas.bucketlist.web.PreventSessionListener</listener-class>
            </listener>
            

            【讨论】:

              【解决方案8】:

              在带有 Java Config 的 Spring Security 3 中,您可以使用 HttpSecurity.sessionManagement():

              @Override
              protected void configure(final HttpSecurity http) throws Exception {
                  http
                      .sessionManagement()
                          .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
              }
              

              Xml 看起来像这样;

              <http create-session="stateless">
                <!-- config -->
              </http>
              

              顺便说一下,NEVER和STATELESS的区别

              NEVER:Spring Security 永远不会创建 HttpSession,但会使用 HttpSession(如果它已经存在)

              STATELESS:Spring Security 永远不会创建 HttpSession,它会 永远不要使用它来获取 SecurityContext

              【讨论】:

              • @ArtemNovikov 你的 Spring Security 版本是什么?从 3.1 开始支持这个未来
              • 这意味着 Spring Security 永远不会创建 HttpSession,而是为其他代码部分敞开大门,这些代码可以通过使用 getSession() 来请求会话创建,如 BalusC 回答中所述
              【解决方案9】:

              从 Servlet 3.0 开始,您可以将这样的代码添加到 ServletContextListenercontextInitialized 方法中,从而使 servlet 容器不以任何方式跟踪会话:

              servletContext.setSessionTrackingModes(Collections.emptySet());
              

              Javadoc.

              【讨论】:

              • 谢谢。与码头一起工作得很好。我需要一种方法来避免创建会话,而不必确保每个 .jsp 都配置了 并且到目前为止它是满足我需求的最佳解决方案。
              猜你喜欢
              • 2012-01-03
              • 2016-03-04
              • 1970-01-01
              • 2022-06-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-11
              • 1970-01-01
              相关资源
              最近更新 更多