如何使用 java 过滤器修改响应正文?
Posted
技术标签:
【中文标题】如何使用 java 过滤器修改响应正文?【英文标题】:how modify the response body with java filter? 【发布时间】:2019-01-20 10:17:10 【问题描述】:我想对 HTTP 响应(json 格式)执行一些过滤逻辑。
我已成功更改响应正文,但是当正文的(字符串)大小发生更改时:我错过了最后一个字符。
为了更简单,我创建了一个简单的 Spring Boot 应用程序,我的 rest 控制器只有 Web 依赖项。
我的休息控制器
@RestController
@RequestMapping("/home/")
public class RestControllerHome
@GetMapping (produces=MediaType.APPLICATION_JSON_VALUE)
public String home()
return " \"name\" : \"Peter\" ";
我的过滤器
@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 // 在写入之前捕获响应
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());
在我的 doFilter 方法中,以下代码...
// 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\" ");
... 给我以下输出: "NAME": "彼得" 这告诉我,代码工作正常。
但是,实际上我想更改正文内容...
// 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\" ");
... 和前面的代码,给了我一个不完整的文本体作为输出: ** "名称" : "**********
我做错了什么? 我的应用程序有一个更大的 json 主体,过滤器中的逻辑更复杂一些。但是,如果我不让这个工作,我就无法让我的其余代码工作。请帮忙。
我从https://www.leveluplunch.com/java/tutorials/034-modify-html-response-using-filter/获取了Filter和HttpServletResponseWrapper
【问题讨论】:
您可能需要将 Content-Length 标头设置为正确的值。 JBNizet,非常感谢。您很快解决了我的问题,再次感谢您。 【参考方案1】:感谢 JBNizet 的帮助,我发现解决方案是添加 Content Lenght:
String newContent = " \"name\" : \"************r\" ";
response.setContentLength(newContent .length());
response.getWriter().write(newContent);
【讨论】:
我收到getWriter() has already been called for this response
这个解决方案的错误。能够与medium.com/@sportans300/… 合作吗?【参考方案2】:
其实按照上面的回答,你会得到一个错误提示getWriter() has already been called for this response
所以,你可以像下面这样简单地修改最后一行:
String newContent = " \"name\" : \"************r\" ";
response.setContentLength(newContent.length());
response.getOutputStream().write(newContent.getBytes());
【讨论】:
以上是关于如何使用 java 过滤器修改响应正文?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Asp.Net Web API 2 中使用 Owin OAuth2 修改令牌端点响应正文