Java – servlet filter “proxy”, which only acts on the response of the remote endpoint

I need that some HTTP requests must be redirected to the spring boot web application / service, but on the requester side, the spring application does nothing and can also be used as the HTTP client (another service) and the real delivery destination of the request But when the response returns to the spring application (from the destination), I need the spring application to check the response and take action if necessary So:

>HTTP client requests, for example http://someapi.example.com >Network magic passes the request to my spring application, such as http://myproxy.example.com >According to the request, this application / agent does not perform any operation, so the request will be http://someapi.example.com Forward > http://someapi.example.com The service endpoint at returns the HTTP response to the proxy > http://myproxy.example.com The agent at checks this response and may send an alert before returning the response to the original client

So essentially, a filter as a request delivery can do anything and return a response only after the remote service is executed

My best attempt is to set up 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)
    }
}

Can this be done? If so, where will I check the code and respond? Take my code as an example. When I try to click the controller from the browser, I will receive an exception:

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?

Solution

According to the servlet API documentation, the reason you get the IllegalStateException is because you are in servletresponse Attempt to call servletresponse after getoutputstream has been called getWriter. So it seems that the method you need to call is servletresponse getOutputStream().

However, if you try to access the body of the response, the best solution is to wrap the response in a servletresponsewrapper so that data can be captured:

public class MyFilter implements Filter
{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {

    }

    @Override
    public void destroy()
    {

    }

    @Override
    public void doFilter(ServletRequest request,FilterChain chain) throws IOException,ServletException
    {
        MyServletResponseWrapper responseWrapper = new MyServletResponseWrapper((HttpServletResponse) response);
        chain.doFilter(request,responseWrapper);
        if (evaluateResponse(responseWrapper)) {
            // Send an alert
        }
    }

    private boolean evaluateResponse(MyServletResponseWrapper responseWrapper) throws IOException
    {
        String body = responseWrapper.getResponseBodyAsText();

        // Perform business logic on the body text

        return true;
    }

    private static class MyServletResponseWrapper extends HttpServletResponseWrapper
    {
        private ByteArrayOutputStream copyOutputStream;
        private ServletOutputStream wrappedOutputStream;

        public MyServletResponseWrapper(HttpServletResponse response)
        {
            super(response);
        }

        public String getResponseBodyAsText() throws IOException
        {
            String encoding = getResponse().getCharacterEncoding();
            return copyOutputStream.toString(encoding);
        }


        @Override
        public ServletOutputStream getOutputStream() throws IOException
        {
            if (wrappedOutputStream == null) {
                wrappedOutputStream = getResponse().getOutputStream();
                copyOutputStream = new ByteArrayOutputStream();
            }
            return new ServletOutputStream()
            {
                @Override
                public boolean isReady()
                {
                    return wrappedOutputStream.isReady();
                }

                @Override
                public void setWriteListener(WriteListener listener)
                {
                    wrappedOutputStream.setWriteListener(listener);
                }

                @Override
                public void write(int b) throws IOException
                {
                    wrappedOutputStream.write(b);
                    copyOutputStream.write(b);
                }

                @Override
                public void close() throws IOException
                {
                    wrappedOutputStream.close();
                    copyOutputStream.close();
                }
            };
        }
    }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>