【问题标题】:Modify the rendered string of a response in Grails 3 before sending to the client在发送到客户端之前修改 Grails 3 中响应的呈现字符串
【发布时间】:2020-06-11 15:24:47
【问题描述】:

我需要创建一个基准报告,说明是否在总体方案中:在每个请求上缩小 + GZIP 动态 HTML 响应(通过 GSP 生成),由于解析生成的动态 HTML 字符串,这将导致额外的开销然后使用 Java 库进行压缩(这会导致更小的响应大小)实际上比 GZIP 更好,而不需要缩小(这会导致更快的响应时间但更大的响应大小)。我觉得这种“改进”也许微不足道,但我需要基准报告来支持团队。

为此,我像这样修改控制器操作:

// import ...MinifyPlugin
class HomeController {
    def get() {
        Map model = [:]
        String htmlBody = groovyPageRenderer.render(view: "/get", model: model)
        // This adds a few milliseconds and reduce few characters.
        htmlBody = MinifyPlugin.minifyHtmlString(htmlBody)
        render htmlBody
    }
}

但是 Grails 项目有将近一百个动作,对每个现有动作都这样做是不切实际且不可维护的,尤其是在基准测试之后,我们可能决定不缩小 HTML 响应。所以我想改为在Interceptor 中执行此操作:

void afterView() {
    if(response.getContentType().contains("text/html")) {
        // This throws IllegalStateException: getWriter() has already been called for this response
        OutputStream servletOutputStream = response.getOutputStream()

        String htmlBody = new String(servletOutputStream.toByteArray())
        htmlBody = MinifyingPlugin.minifyHtmlString(htmlBody)
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()
        byteArrayOutputStream.write(htmlBody.getBytes())

        response.setCharacterEncoding("UTF-8")
        response.setContentType("text/html")
        response.outputStream << byteArrayOutputStream
    }
}

但是似乎响应体一旦进入afterView拦截器就不可能修改...?那么是否有任何其他方法可以使用 Grails 3 拦截器来做到这一点,或者我应该手动更新我们拥有的每个控制器操作并在那里执行修改?

【问题讨论】:

  • 我认为最好在您的 servlet 容器或 Web 服务器中执行此操作,而不是在应用程序层执行此操作。如果你使用 tomcat 它有这个设置。
  • 埃里克说的是对的。与此分开......“但似乎响应体一旦进入afterView拦截器就不可能修改......?”,没错。 afterView 在响应写入后调用,所以为时已晚。

标签: html servlets grails


【解决方案1】:

这就是我喜欢使用拦截器的目的。

拦截器的after()部分可以在模型从控制器返回后作用于模型(其中'before()'在请求发送到控制器之前作用于请求)

这允许您在返回客户端之前处理一组端点(或一个特定端点)的所有数据

如果你想渲染到一个视图,你可以在拦截器中而不是在控制器中进行;你只是从控制器返回数据

【讨论】:

  • after() 和 before() 方法还没有初始化内容类型,因此我不能只过滤掉 text/html 响应。
  • 如果您需要 Interceptor 中的 contentType,只需使用 request.getContentType()。该请求包含您可用的标头中的所有信息。
  • 当您在before()after() 方法中使用getContentType() 时,contentType 为空。 contentType 只会在通过after() 后才会被初始化,因此只有在afterView() 中才能获得实际的contentType
  • 我不知道你为什么这么认为。我经常在我的 HandlerInterceptors 中使用它,它工作正常。这是一个包含它的类,现在在几个生产站点中工作:github.com/orubel/Beapi-API-Framework/blob/master/grails-app/…。它在 Grails 2/3 中运行良好,在 Spring/Springboot HandlerInterceptors 中运行良好
猜你喜欢
  • 2022-11-04
  • 1970-01-01
  • 2015-08-16
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
相关资源
最近更新 更多