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を見てください。


さて、コード:

このコードは出力を (2 つの方法で) バッファリングするため、疑似出力の後にヘッダーを追加すると機能します。実際、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 に答える