6

我想知道是否可以使用过滤器(在我的情况下是 CorsFilter)来测量时间并将所花费的时间放在消息本身上。我知道以下工作正常:

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
  long startTime = System.nanoTime();
  chain.doFilter(request, response);
  long endTime = System.nanoTime();
  System.out.println("Time: " + (endTime - startTime) );
}

这当然会以秒为单位输出总时间。我想将时间放入返回响应的标头中,以便接收者可以查看标头并查看处理时间。以下代码不起作用:

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
  long startTime = System.nanoTime();
  if(response instanceof HttpServletResponse) {
    HttpServletResponse httpResp = (HttpServletResponse)response;
    httpResp.addHeader("Start-time", Long.toString(startTime));
  }

  chain.doFilter(request, response);
  long endTime = System.nanoTime();
  if(response instanceof HttpServletResponse) {
    HttpServletResponse httpResp = (HttpServletResponse)response;
    httpResp.addHeader("End-time", Long.toString(endTime));
  }
}

标头仅包括开始时间而不包括结束时间。我假设这是因为消息已经发送,所以修改对象将无效。

有没有人有一个优雅/聪明的解决方案来通过使用过滤器将时间放入标题中?

谢谢,菲尔

更新

我研究了使用 HttpServletResponseWrapper 来解决此解决方案。这仍然无法在响应标头上输出 XXX-EndTime 或 YYY-EndTime。

@Override
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
  long startTime = System.nanoTime();

  if(response instanceof HttpServletResponse) {
    HttpServletResponse httpResp = (HttpServletResponse)response;
    httpResp.addHeader("Access-Control-Allow-Origin", "*");
    httpResp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
    httpResp.addHeader("Allow", "GET, HEAD, OPTIONS");
    httpResp.addHeader("Access-Control-Allow-Headers", "*");
    httpResp.addHeader("A-Runtime", Long.toString(startTime));
  }

  OutputStream out = response.getOutputStream();

  GenericResponseWrapper wrapper = new GenericResponseWrapper((HttpServletResponse) response);

  chain.doFilter(request,wrapper);

  out.write(wrapper.getData());

  if(response instanceof HttpServletResponse) {
HttpServletResponse httpResp = (HttpServletResponse)response;
httpResp.addHeader("XXX-EndTime", Long.toString(System.nanoTime() - startTime));

    wrapper.addHeader("YYY-EndTime", Long.toString(System.nanoTime() - startTime));
  }

  out.close();
}
4

1 回答 1

2

看看HttpServletResponseWrapper


好的,然后代码:

此代码缓冲输出(以两种方式),因此在伪输出之后添加标题。实际上 addHeader 可以通过输出来实现,所以我们很幸运它可以工作。边界案例代码。如果不走运, addHeader 将不得不被覆盖。

请注意,当我尝试时,我的测试应用程序中只调用了 getOutputStream 。可以选择 getPrintWriter 或 getOutputStream。

private static class PostponingResponseWrapper extends HttpServletResponseWrapper {

    private ByteArrayOutputStream bos;
    private ServletOutputStream outputStream;
    private StringWriter sw;
    private PrintWriter printWriter;
    private boolean usingOutputStream;
    private boolean usingWriter;

    public PostponingResponseWrapper (HttpServletResponse response) {
        super(response);
        bos = new ByteArrayOutputStream();
        outputStream = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                bos.write(b);
            }
        };
        sw = new StringWriter();
        printWriter = new PrintWriter(sw);
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        usingWriter = true;
        LOGGER.info("getWriter usingWriter {}, usingOutputStream {}", usingWriter, usingOutputStream);
        return printWriter;
    }

    @Override
    public void flushBuffer() throws IOException {
        LOGGER.info("flushBuffer");
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        usingOutputStream = true;
        LOGGER.info("getOutputStream usingWriter {}, usingOutputStream {}", usingWriter, usingOutputStream);
        ServletOutputStream out = new ServletOutputStream() {
            @Override
            public void write(int b) throws IOException {
                outputStream.write(b);
            }
        };
        return out;
    }

    public void finish() throws IOException {
        LOGGER.info("finish");
        if (usingWriter) {
            super.getWriter().print(sw.toString());
        } else if (usingOutputStream) {
            super.getOutputStream().write(bos.toByteArray());
        }
    }
}

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    PostponingResponseWrapper responseWrapper =
            new PostponingResponseWrapper (httpServletResponse);
    responseWrapper.addHeader("Before", "Already-Worked");
    chain.doFilter(request, responseWrapper);
    responseWrapper.addHeader("After", "And-Now-This");
    responseWrapper.finish(); // Writes the actual response
}
于 2012-11-20T10:28:28.453 回答