我需要将某些HTTP请求重定向到Spring Boot Web应用程序/服务,但是在请求端,Spring应用程序什么都不做,并且充当HTTP客户端(另一个服务)和请求的真实之间的直通目的地.但是当响应回到Spring应用程序(来自该目的地)时,我需要Spring应用程序能够检查响应,并在需要时可能对其采取措施.所以:
HTTP客户端向http://someapi.example.com发出请求
网络魔术将请求路由到我的Spring应用程序,比如http://myproxy.example.com
根据请求,此app/proxy不执行任何操作,因此请求将在http://someapi.example.com上转发
http://someapi.example.com上的服务端点将HTTP响应返回给代理
http://myproxy.example.com上的代理检查此响应,并可能在将响应返回给原始客户端之前发送警报
基本上,一个过滤器充当请求的传递,并且在远程服务执行并返回响应之后才真正做任何事情.
到目前为止,我最好的尝试是设置一个servlet过滤器:
@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) } }
这可能吗?如果是这样,我在哪里放置检查和响应的代码?使用我的代码时,我尝试从浏览器访问控制器时会抛出异常:
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
有任何想法吗?
根据Servlet API文档,您获得该文档的原因IllegalStateException
是因为您尝试调用ServletResponse.getWriter
之后ServletResponse.getOutputStream
已经响应了响应.所以看来你需要调用的方法是ServletResponse.getOutputStream()
.
但是,如果您尝试访问响应的主体,最佳解决方案是将响应包装在一个ServletResponseWrapper
以便您可以捕获数据:
public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, 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(); } }; } } }