我需要某些 HTTP 请求必须重定向到 Spring Boot Web 应用程序/服务,但在请求端,Spring 应用程序什么都不做,而是充当 HTTP 客户端(另一个服务)和请求的真实目的地.但是当响应返回到 Spring 应用程序(从那个目的地)时,我需要 Spring 应用程序能够检查响应并在需要时可能对其采取行动.所以:
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:
本质上,过滤器充当请求的传递,并且仅在远程服务执行并返回响应之后真正执行任何操作.
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.
到目前为止,我最好的尝试是设置一个 servlet 过滤器:
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有什么想法吗?
推荐答案根据 Servlet API 文档,您收到 IllegalStateException 的原因是因为您试图调用 ServletResponse.getWriter 在 ServletResponse.getOutputStream 之后已经在响应上被调用.所以看起来你需要调用的方法是ServletResponse.getOutputStream().
Per the Servlet API documentation, the reason you are getting the IllegalStateException is because you are attempting to call ServletResponse.getWriter after ServletResponse.getOutputStream has already been called on the response. So it appears that the method you need to call is ServletResponse.getOutputStream().
但是,如果您尝试访问响应的正文,最好的解决方案是将响应包装在 ServletResponseWrapper 中,以便您可以捕获数据:
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:
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(); } }; } } }更多推荐
Servlet 过滤器“代理"仅作用于来自远程端点的响应
发布评论