I have a need where certain HTTP requests must be redirected to a Spring Boot web app/service, but that on the request-side, the Spring app does nothing and acts as a passthrough between the HTTP client (another service) and the request's true destination. But when the response comes back to the Spring app (from that destination), I need the Spring app to be able to inspect the response and possibly take action on it if need be. So:
- HTTP client makes a request to, say, http://someapi.example.com
- Network magic routes the request to my Spring app at, say, http://myproxy.example.com
- On the request, this app/proxy does nothing, and so the request is forwarded on http://someapi.example.com
- The service endpoint at http://someapi.example.com returns an HTTP response back to the proxy
- The proxy at http://myproxy.example.com inspects this response, and possibly sends an alert before returning the response back to the original client
So essentially, a filter that acts as a pass-through on the request, and only really does anything after the remote service has executed and returned a response.
My best attempt thus far has been to setup a servlet filter:
@Override
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response)
// How and where do I put my code?
if(responseContainsFizz(response)) {
// Send an alert (don't worry about this code)
}
}
Is this possible to do? If so, where do I put the code that inspects and acts upon the response? With my code the way it is I get exceptions thrown when trying to hit a controller from a browser:
java.lang.IllegalStateException: STREAM
at org.eclipse.jetty.server.Response.getWriter(Response.java:910) ~[jetty-server-9.2.16.v20160414.jar:9.2.16.v20160414]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_92]
rest of stack trace omitted for brevity
Any ideas?
Per the Servlet API documentation, the reason you are getting the
IllegalStateException
is because you are attempting to callServletResponse.getWriter
afterServletResponse.getOutputStream
has already been called on the response. So it appears that the method you need to call isServletResponse.getOutputStream()
.However, if you are trying to access the body of the response, the best solution is to wrap the response in a
ServletResponseWrapper
so that you can capture the data:The response can be easy manipulated/replaced/extended e with a filter and a response wrapper.
In the filter before the call
chain.doFilter(request, wrapper)
you prepare aPrintWriter
for the new response content and the wrapper object.After the call
chain.doFilter(request, wrapper)
is the actuall response manipulation.The wrapper is used to get access to the response as String.
The Filter:
The Response Wrapper:
The Test Servlet:
Test Urls:
More Info and examples about filters:
http://www.oracle.com/technetwork/java/filters-137243.html#72674
http://www.leveluplunch.com/java/tutorials/034-modify-html-response-using-filter/
https://punekaramit.wordpress.com/2010/03/16/intercepting-http-response-using-servlet-filter/