我可以关闭 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 不会通过设置隐式执行此操作<%@page session="false"%>
.
如果您真正关心的是禁用在 HttpSession
幕后使用的 cookie,那么您可以在 Java EE 5 / Servlet 2.5 中仅在特定于服务器的 webapp 配置中这样做。例如在 Tomcat 中,您可以在 <Context>
元素中将 cookies
属性设置为 false
。
<Context cookies="false">
另见Tomcat specific documentation。这样,会话将不会保留在未重写 URL 的后续请求中——仅当您出于某种原因从请求中获取它时。毕竟,如果你不需要它,只是不要抓住它,那么它根本不会被创建/保留。
或者,如果您已经在使用 Java EE 6 / Servlet 3.0 或更新版本,并且真的想通过 web.xml
来实现,那么您可以使用 web.xml
中的新 <cookie-config>
元素,如下所示归零-超出最大年龄:
<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 开始,您可以将这样的代码添加到 ServletContextListener
的 contextInitialized
方法中,从而使 servlet 容器不以任何方式跟踪会话:
servletContext.setSessionTrackingModes(Collections.emptySet());
Javadoc.
【讨论】:
谢谢。与码头一起工作得很好。我需要一种方法来避免创建会话,而不必确保每个 .jsp 都配置了 并且到目前为止它是满足我需求的最佳解决方案。以上是关于我可以关闭 web.xml 中的 HttpSession 吗?的主要内容,如果未能解决你的问题,请参考以下文章
IntelliJ Idea标记红色web.xml运行良好[关闭]
哪个更适合专业使用(web.xml(部署描述符)或@WebServlet注释?[关闭]