3

I'm writing a logging filter that logs all HTTP requests / responses for a web app running in Jersey. ContainerResponseFilter seems to a straight forward solution and I've managed to get it to work.

Next step is to log the IP of the requests. Is there a way to do that from inside the ContainerResponseFilter ?

Binh Tran
  • 133
  • 3
  • 8

1 Answers1

13

Short answer:

@Provider
public class YourContextFilter implements ContainerRequestFilter {

    @Context
    private HttpServletRequest sr;

    @Override
    public synchronized void filter(ContainerRequestContext request) throws IOException {
        /*
         * Returns the Internet Protocol (IP) address of the client or 
         * last proxy that sent the request. For HTTP servlets, same as 
         * the value of the CGI variable REMOTE_ADDR.
         */
        String ip = sr.getRemoteAddr();
        // ... log it ...
    }

}

EDIT
(regarding the wish for a more detailed answer)

Afaig:

The @Context annotation allows to inject JAX-RS–specific components (one might say you are able to inject contextual information objects). JAX-RS itself is a Java based specification for RESTful Web Services over HTTP protocol. So we are able to inject stuff like:

javax.ws.rs.core.UriInfo
javax.ws.rs.core.Request
javax.ws.rs.core.SecurityContext

and also
javax.servlet.http.HttpServletRequest

In the IOC Chapter of the Jersey docs, you will find these notes:

[...] Jersey implementation allows you to directly inject HttpServletRequest instance into your JAX-RS components [...] - https://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e2401

[...] The exception exists for specific request objects which can injected even into constructor or class fields. For these objects the runtime will inject proxies which are able to simultaneously server more request. These request objects are HttpHeaders, Request, UriInfo, SecurityContext. These proxies can be injected using the @Context annotation. [...]

[...] When deploying a JAX-RS application using servlet then ServletConfig, ServletContext, HttpServletRequest and HttpServletResponse are available using @Context. [...]

And if you do so, you inject in fact a Proxy named org.apache.catalina.connector.RequestFacade (link). This proxy functioned as your direct hotline to your Coyote (HTTP Connector) and thereby to the Coyote request object (link).

Hope this was helpful somehow :) - Have a nice day.

zyexal
  • 1,570
  • 16
  • 23
  • Wow, that's amazing. Can you tell me the long answer so that I understand how does the `HttpServletRequest` is injected? – Binh Tran Oct 05 '14 at 18:34
  • A bit longer now, hope this helps. Feel free to ask for improvements, especially if i did a mistake. – zyexal Oct 06 '14 at 19:11
  • 1
    This does not work for me. The HttpServletRequest is null when my filter executes. It all looks correct, just not getting the proxy wired in. Anyone else have the same issue? – Michael Andrews Sep 30 '15 at 16:52
  • Ah. Never mind. Spring was managing my Jersey filter. Once I allowed Jersey to manage it, it all worked. This leads to a dilemma though. How to allow Spring to manage the filter so I get AOP timing, but still allow jersey to wire in the HttpServletRequest (Spring knowns nothing about the request). Might just punt on the Spring functionality. – Michael Andrews Sep 30 '15 at 17:05
  • What version of Jersey 2.0 does this work? `2.25.1` does not work for me. – kevinarpe Nov 24 '17 at 03:43
  • 1
    @kevinarpe I have no idea what you mean by "does not work". I've tested it with `2.25.1` and it *works* as expected. You might want to formulate your problem as a question. – zyexal Nov 24 '17 at 18:15
  • How does this work with threaded code, for example if you `register(YourContextFilter())` rather than `register(YourContextFilter.class)`? – Mike Holler Aug 21 '19 at 18:42