如何在 Spring 中缩小动态 HTML 响应?

Posted

技术标签:

【中文标题】如何在 Spring 中缩小动态 HTML 响应?【英文标题】:How do I minify dynamic HTML responses in Spring? 【发布时间】:2018-03-07 12:09:24 【问题描述】:

按照 Google 的 pagespeed 建议,我希望缩小我的 Spring 应用程序的 html 响应。我不是指 GZip,我是指在将 HTML 发送到网络之前从 HTML 中删除 cmets 和空格。

我想动态而不是在我的模板中执行此操作。我的模板包含许多有用的 cmets,但不应成为响应的一部分。

下面是我的控制器;

@Controller
public class IndexController 

    @GetMapping("/")
    public ModelAndView index() 
        Data data = ....
        return new ModelAndView("index", data);
    

【问题讨论】:

对于那些认为缩小 HTML 是个坏主意的人,请参阅这个 google 链接了解我为什么要这样做:developers.google.com/speed/docs/insights/MinifyResources 【参考方案1】:

我设法通过在 Spring 中添加一个使用 com.googlecode.htmlcompressorjavax.servlet.Filter 组件来做到这一点

首先是Filter

@Component
public class HtmlFilter implements Filter 
    protected FilterConfig config;

    public void init(FilterConfig config) throws ServletException 
        this.config = config;
    

    public void destroy() 
    

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws ServletException, IOException 
        ServletResponse newResponse = response;

        if (request instanceof HttpServletRequest) 
            newResponse = new CharResponseWrapper((HttpServletResponse) response);
        

        chain.doFilter(request, newResponse);

        if (newResponse instanceof CharResponseWrapper) 
            String text = newResponse.toString();
            if (text != null) 
                HtmlCompressor htmlCompressor = new HtmlCompressor();
                response.getWriter().write(htmlCompressor.compress(text));
            
        
    

和相关的CharResponseWrapper;

class CharResponseWrapper extends HttpServletResponseWrapper 
    protected CharArrayWriter charWriter;
    protected PrintWriter writer;
    protected boolean getOutputStreamCalled;
    protected boolean getWriterCalled;

    public CharResponseWrapper(HttpServletResponse response) 
        super(response);

        charWriter = new CharArrayWriter();
    

    public ServletOutputStream getOutputStream() throws IOException 
        if (getWriterCalled) 
            throw new IllegalStateException("getWriter already called");
        

        getOutputStreamCalled = true;
        return super.getOutputStream();
    

    public PrintWriter getWriter() throws IOException 
        if (writer != null) 
            return writer;
        
        if (getOutputStreamCalled) 
            throw new IllegalStateException("getOutputStream already called");
        
        getWriterCalled = true;
        writer = new PrintWriter(charWriter);
        return writer;
    

    public String toString() 
        String s = null;

        if (writer != null) 
            s = charWriter.toString();
        
        return s;
    

效果非常好。把一个难看的 html 转换成这样;

<!DOCTYPE HTML>
<html>
<head>
    <title>
        A Simple
        <!--        Test-->
        HTML Document
        <!--        Test-->

    </title>



</head>
<body>
                 <p>This is a very simple HTML document</p>


                 <!--        Test-->



<p>It only has two<!--        Test--> paragraphs</p>

                 <!--        Test-->

</body>
</html>

进入这个;

<!DOCTYPE HTML> <html> <head> <title> A Simple HTML Document </title> </head> <body> <p>This is a very simple HTML document</p> <p>It only has two paragraphs</p> </body> </html>

【讨论】:

如果不使用统计,htmlCompressor可能会缓存在类成员中 我错了还是CharResponseWrapper类中的方法getOutputStream()不是必需的并且可以安全删除?似乎无论如何都可以工作......

以上是关于如何在 Spring 中缩小动态 HTML 响应?的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot SSE(服务器发送事件):如何动态发送响应

如何让图像响应屏幕尺寸但不逐渐缩小?

如何在具有固定高度的 flex 容器中缩小响应式图像

使用Java,Spring进行基于配置文件,可切换的JSON缩小

在 Spring Data rest json Response 中动态过滤实体字段

Spring Boot:将 JSON 响应包装在动态父对象中