我可以关闭 web.xml 中的 HttpSession 吗?

Posted

技术标签:

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

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

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

【问题讨论】:

多么有趣的问题。我有一种情况,使用 Tomcat,没有为我创建会话,所以我正在寻找是否有办法在 web.xml 中打开会话 on。 :D 【参考方案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 都配置了 并且到目前为止它是满足我需求的最佳解决方案。

以上是关于我可以关闭 web.xml 中的 HttpSession 吗?的主要内容,如果未能解决你的问题,请参考以下文章

关于 Session 的深入探讨

IntelliJ Idea标记红色web.xml运行良好[关闭]

哪个更适合专业使用(web.xml(部署描述符)或@WebServlet注释?[关闭]

将 .properties 文件中的值设置为 web.xml

什么是 web.xml 文件,我可以用它做什么?

Tomcat关闭:contextDestroyed期间的类加载不起作用