Написание фильтра сервлетов с Quarkus, который изменяет тело ответа - PullRequest
1 голос
/ 12 апреля 2020

Я пытаюсь написать фильтр сервлетов в Quarkus, который изменяет тело ответа. По сути, я выполнил шаги, описанные в следующей статье, чтобы убедиться, что ничего не пропустил: https://medium.com/@sportans300 / fiddling-with-httpresponses-in- java -2a269cd5a474

Итак, Метод фильтра выглядит следующим образом:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws IOException, ServletException {

    if (request instanceof HttpServletRequestImpl) {
        String url = ((HttpServletRequestImpl) request).getRequestURL().toString();
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        if (url.endsWith("/index.html")) {

            ServletResponseWrapper wrappedResp = new ServletResponseWrapper((HttpServletResponse) response);

            filterChain.doFilter(request, wrappedResp);

            String respBody = wrappedResp.toString();

            if (wrappedResp.getContentType().contains("text/html")) {
                String msg = "<html><head></head><body>hello world</body></html>";
                response.setContentLength(msg.length());
                response.getWriter().write(msg);
            }
            else {
                System.out.println("-- Just return original resonse");
                response.getWriter().append(respBody);
            }
            return;
        }
    }

    filterChain.doFilter(request, response);
}

И ResponseWrapper так:

public class ServletResponseWrapper extends HttpServletResponseWrapper {

    private final ByteArrayOutputStream capture;
    private ServletOutputStream output;
    private PrintWriter writer;

    public ServletResponseWrapper(HttpServletResponse response) throws IOException {
        super(response);
        capture = new ByteArrayOutputStream(response.getBufferSize());
    }

    @Override
    public ServletOutputStream getOutputStream() {
        if (writer != null) {
            throw new IllegalStateException("getWriter() has already been called on this response.");
        }

        if (output == null) {
            output = new ServletOutputStream() {
                @Override
                public void write(int b) throws IOException {
                    capture.write(b);
                }

                @Override
                public void write(byte b[]) throws IOException {
                    capture.write(b);
                }

                @Override
                public void write(byte b[], int off, int len) throws IOException {
                    capture.write(b, off, len);
                }

                @Override
                public void flush() throws IOException {
                    capture.flush();
                }

                @Override
                public void close() throws IOException {
                    capture.close();
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setWriteListener(WriteListener arg0) {
                }
            };
        }

        return output;
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        if (output != null) {
            throw new IllegalStateException("getOutputStream() has already been called on this response.");
        }

        if (writer == null) {
            writer = new PrintWriter(new OutputStreamWriter(capture, getCharacterEncoding()));
        }

        return writer;
    }

    public void close() throws IOException {
        if (writer != null) {
            writer.close();
        }
        if (output != null) {
            output.close();
        }
    }

    @Override
    public void flushBuffer() throws IOException {
        System.out.println("-- flush buffer");
        if (writer != null) {
            writer.flush();
        } else if (output != null) {
            output.flush();
        }
    }

    public byte[] getResponseData() throws IOException {
        if (writer != null) {
            writer.close();
        } else if (output != null) {
            output.close();
        }
        return capture.toByteArray();
    }

    @Override
    public String toString() {
        try {
            return new String(getResponseData());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

То, что происходит, это то, что кажется, что ответ уже зафиксирован, и я не могу изменить contentLength и тело больше. Кажется, Undertow уже начал отправлять заголовки во время filterChain.doFilter(request, wrappedResp). Браузер получает Content-Length, установленную на длину исходного ответа, а тело вообще не принимается (страница продолжает загружаться).

UPDATE : я тестировал тот же веб-фильтр на Wildfly 19 и OpenLiberty; фильтр работает как положено. Таким образом, проблема указана для * Quarkus c.

ОБНОВЛЕНИЕ 2 : Кажется, проблема в quarkus: только для разработчиков. Я открыл вопрос: https://github.com/quarkusio/quarkus/issues/8546

...