Я пытаюсь написать фильтр сервлетов в 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