how modify the response body with java filter?
Thanks to the help of JBNizet, I found that the solution was to add the Content Lenght:
String newContent = "{ \"name\" : \"************r\" }";
response.setContentLength(newContent .length());
response.getWriter().write(newContent);
JaimeRG
Updated on July 20, 2022Comments
-
JaimeRG almost 2 years
I want to perform some filter logic to HTTP responses (which are in json format).
I had successfully change the response body, but when the (string) size of the body changes: I am getting missing the last characters.
To make it simpler, I had created a simple Spring Boot application, with only Web dependency for my rest controller.
My Rest Controller
@RestController @RequestMapping("/home/") public class RestControllerHome { @GetMapping (produces=MediaType.APPLICATION_JSON_VALUE) public String home() { return "{ \"name\" : \"Peter\" }"; } }
My Filter
@Component public class MyFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { HtmlResponseWrapper capturingResponseWrapper = new HtmlResponseWrapper((HttpServletResponse) response); filterChain.doFilter(request, capturingResponseWrapper); if (response.getContentType() != null && response.getContentType().contains("application/json")) { String content = capturingResponseWrapper.getCaptureAsString(); // This code works fine //response.getWriter().write(content.toUpperCase()); // This code doesn't works because the content size is changed response.getWriter().write("{ \"name\" : \"************r\" }"); } } @Override public void init(FilterConfig arg0) throws ServletException { } }
HttpServletResponseWrapper // capture the response before it is written
public class HtmlResponseWrapper extends HttpServletResponseWrapper { private final ByteArrayOutputStream capture; private ServletOutputStream output; private PrintWriter writer; public HtmlResponseWrapper(HttpServletResponse response) { 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) { // inner class - lets the wrapper manipulate the response output = new ServletOutputStream() { @Override public void write(int b) throws IOException { capture.write(b); } @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; } @Override public void flushBuffer() throws IOException { super.flushBuffer(); if (writer != null) { writer.flush(); } else if (output != null) { output.flush(); } } public byte[] getCaptureAsBytes() throws IOException { if (writer != null) { writer.close(); } else if (output != null) { output.close(); } return capture.toByteArray(); } public String getCaptureAsString() throws IOException { return new String(getCaptureAsBytes(), getCharacterEncoding()); } }
In my doFilter method, the following code ...
// This code works fine response.getWriter().write(content.toUpperCase()); // This code doesn't works because the content size is changed //response.getWriter().write("{ \"name\" : \"************r\" }");
... gives my the following output : {"NAME": "PETER"} Which tell me, that the code is working properly.
But, in reality I want to change the body content ...
// This code works fine //response.getWriter().write(content.toUpperCase()); // This code doesn't works because the content size is changed response.getWriter().write("{ \"name\" : \"************r\" }");
... and the previous code, is giving me an incomplete text body as output: **{ "name" : "**********
What am I doing wrong? My app have a bigger json body, and a little more complex logic in the filter. But, if I dont get this working I am not being able to make the rest of my code work. Please, help.
I took the Filter and HttpServletResponseWrapper from https://www.leveluplunch.com/java/tutorials/034-modify-html-response-using-filter/
-
pkgajulapalli over 4 yearsI'm getting
getWriter() has already been called for this response
error with this solution. Was able to work with medium.com/@sportans300/…?