我需要在Java代码中获取请求对象(request object)。由于某些原因,我不能将该对象传递给我的代码。是否有一种方法可以像这样说:getCurrentHTTPServletRequest
?
我可以安全地假设我处于Servlet上下文中。
我需要在Java代码中获取请求对象(request object)。由于某些原因,我不能将该对象传递给我的代码。是否有一种方法可以像这样说:getCurrentHTTPServletRequest
?
我可以安全地假设我处于Servlet上下文中。
如果需要,你应该将它传递下去。其他的做法基本上都会很丑陋。
你可以使用ThreadLocal
变量——在获取请求时为该特定线程设置上下文,并在以后获取它。只要你只需要在线程中访问请求,并且不进行任何奇怪的异步请求处理,那么这种方法就可行。但是,由于刚才提到的原因,这种方法比较脆弱。
然而,我强烈建议你明确你的依赖关系。要么将Servlet请求传递下去,要么只传递需要的部分。
假设您无法将请求对象传递到调用堆栈下面,则需要一些共享机制,这并不理想,但有时是必要的。
Spring为此提供了RequestContextFilter。它使用了 ThreadLocal
,允许代码通过RequestContextHolder获取当前请求。请注意,此过滤器不要求您使用 Spring 的任何其他部分:
Servlet 2.3 Filter,通过 LocaleContextHolder 和 RequestContextHolder 将请求暴露给当前线程。在 web.xml 中注册为过滤器。
此过滤器主要用于与第三方 Servlet(例如 JSF FacesServlet)一起使用。在 Spring 自己的 Web 支持中,DispatcherServlet 的处理已经足够完善。
如果您要使用 ThreadLocal
,那么最好使用现有的、可工作的解决方案,而不是冒险出现 ThreadLocal
代码容易出现的错误。
Jon Skeet已经讲解了几乎所有内容,但是需要对他的建议“只需所需部分”进行澄清 - 如果您需要传递请求参数,但不需要依赖于HttpServletRequest
,请传递request.getParameterMap()
。
另外,在使用ThreadLocal
选项时可以扩展一下 - 您可以有一个Filter
来处理所有传入的请求,并在其中设置请求。
public final static ThreadLocal<HttpServletRequest> httpServletRequestTL =
new ThreadLocal<HttpServletRequest>();
因为您在每个请求中都设置了它(注意过滤器映射),所以您不必担心servlet容器线程池 - 您将始终拥有当前请求。
P.S.这是skaffman提出的spring实用程序背后的逻辑 - 我与他一起推荐稳定的组件,而不是自己制作。
没有Servlet API可以做到这一点。然而,Tomcat提供了一个API调用来实现这个功能。
HttpServletRequest request = (HttpServletRequest)org.apache.catalina.core.ApplicationFilterChain.getLastServicedRequest();
此方法将获取当前线程传递给Servlet进行服务的最后一个请求。
要使此方法正常工作,Tomcat必须处于“严格的Servlet合规性”模式。如果没有,您需要通过添加以下JVM参数来启用它:
org.apache.catalina.STRICT_SERVLET_COMPLIANCE=true
假设由于某些疯狂的业务相关原因,顶级servlet确实是禁忌,仍然有定义ServletFilter
的选项来预览请求并将其放入ThreadLocal中。假设web.xml
也不是神圣不可侵犯的。
但我同意Jon Skeet的看法,这会非常丑陋。我会编写代码,然后尝试找到其他工作。 :)
实际上,考虑到过滤器可以完全从接收servlet中夺取控制权,您可以使用此技术将代码转移到自己的servlet中,执行任何您想要的操作,然后运行其他“官方”servlet...或者沿着这些线路做任何其他事情。其中一些解决方案甚至允许您正确而强大地处理请求数据。