【问题标题】:how modify the response body with java filter?如何使用 java 过滤器修改响应正文?
【发布时间】: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,非常感谢。您很快解决了我的问题,再次感谢您。

标签: java json rest spring-boot filter


【解决方案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());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-18
    • 2015-06-20
    • 1970-01-01
    • 2017-06-25
    • 2020-07-21
    • 2017-01-02
    • 1970-01-01
    相关资源
    最近更新 更多