Get the HttpServletRequest (request) object from Java code
I need to get hold of the request object in Java code. I can't pass this object down to my code for certain reasons. Is there any way I can say something like: getCurrentHTTPServletRequest
?
It is safe for me to assume that 开发者_JS百科I am in a Servlet Context.
Well you should pass it down if you need it. Anything else you do is going to be ugly, basically.
You could use a ThreadLocal
variable - basically set the context for that particular thread when you get the request, and then fetch it later on. That will work so long as you only need to get at the request within the thread that's processing it - and so long as you don't do any funky asynchronous request handling. It's brittle though, for precisely those reasons.
However, I would strongly advise you to be explicit about your dependencies instead. Either pass the servlet request down, or just the bits that you need.
Assuming you're not able to pass the request object down the call stack, then some kind of sharing mechanism becomes necessary, which is not ideal, but sometimes necessary.
Spring provides the RequestContextFilter for just this purpose. It uses ThreadLocal
, and allows the code to fetch the current request via RequestContextHolder. Note that this filter does not require you to use any other part of Spring:
Servlet 2.3 Filter that exposes the request to the current thread, through both LocaleContextHolder and RequestContextHolder. To be registered as filter in web.xml.
This filter is mainly for use with third-party servlets, e.g. the JSF FacesServlet. Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient.
If you're going to use ThreadLocal
, then better to use an existing, working solution, rather than risk bugs creeping in, which ThreadLocal
code is prone to.
Jon Skeet said practically everything, but one clarification to his advice "just the bits that you need" - if you need your request parameters passed down, but you don't need a dependency on HttpServletRequest
, pass request.getParameterMap()
.
And extending a bit on the ThreadLocal
option - you can have a Filter
which handles all incoming requests, and sets the request in a
public final static ThreadLocal<HttpServletRequest> httpServletRequestTL =
new ThreadLocal<HttpServletRequest>();
Because you are setting it on each request (careful with the filter mapping), you won't have to worry about the servlet-container thread pool - you will always have the current request.
P.S. this is the logic behind the spring utility proposed by skaffman - I join him recommending the stable component, rather than making your own.
There is no servlet API to do this. However, Tomcat does provide an API call to do this,
HttpServletRequest request = (HttpServletRequest)org.apache.catalina.core.ApplicationFilterChain.getLastServicedRequest();
This will get the last request passed to a servlet for servicing from the current thread.
For this to work, the Tomcat must be in "Strict Servlet Compliance" mode. If not, you need to enable it by adding this JVM parameter:
org.apache.catalina.STRICT_SERVLET_COMPLIANCE=true
Assuming the top-level servlet really is taboo for some crazy business-related reason, there is still the option of defining a ServletFilter
to pre-view the request and stuff it into a ThreadLocal. Assuming that the web.xml
is not also sacrosanct.
But I agree with Jon Skeet in that this would be very ugly. I'd code this up and then try to find a different job. :)
Actually, given the fact that a filter can totally wrest away control from the receiving servlet, you could use this technique to divert the code to a servlet of your own, do whatever you want, and THEN run the other, "official" servlet... or anything else along those lines. Some of those solutions would even allow you to deal correctly and robustly with your request data.
精彩评论