Измените обработанную строку ответа в Grails 3 перед отправкой клиенту.

Мне нужно создать контрольный отчет о том, есть ли в общей схеме: минимизация + динамические HTML-ответы GZIP (сгенерированные с помощью 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, или мне следует обновить каждое действие контроллера, которое у нас есть, вручную и вместо этого выполнить модификацию?


person Gideon    schedule 11.06.2020    source источник
comment
Я думаю, было бы лучше сделать это в контейнере сервлета или на веб-сервере, а не на уровне приложения. Если вы используете tomcat, у него есть настройки для этого.   -  person erichelgeson    schedule 11.06.2020
comment
То, что сказал Эрик, верно. Отдельно от этого... Но кажется, что модификация тела ответа невозможна, как только он входит в перехватчик afterView...?, это правильно. afterView вызывается после того, как ответ был написан, так что уже слишком поздно.   -  person Jeff Scott Brown    schedule 11.06.2020


Ответы (1)


Это то, для чего мне нравится использовать Interceptors.

Часть after() перехватчика может воздействовать на модель после того, как она будет возвращена из контроллера (где 'before()' воздействует на запрос до того, как он будет отправлен контроллеру)

Это позволяет вам манипулировать всеми данными для набора конечных точек (или одной конкретной конечной точки) перед возвратом клиенту.

Если вы хотите выполнить визуализацию в представлении, вы делаете это в перехватчике, а не в контроллере; вы просто возвращаете данные из контроллера

person Orubel    schedule 11.06.2020
comment
Методы after() и before() еще не инициализируют тип контента, поэтому я не могу отфильтровать только ответы text/html. - person Gideon; 11.06.2020
comment
Если вам нужен contentType в Interceptor, просто используйте request.getContentType(). В запросе есть вся доступная вам информация из заголовков. - person Orubel; 12.06.2020
comment
contentType имеет значение null, когда вы используете getContentType() внутри методов before() и after(). contentType будет инициализирован только после прохождения через after(), и поэтому только в afterView() вы сможете получить настоящий contentType. - person Gideon; 13.06.2020
comment
Я не знаю, почему ты так думаешь. Я часто использую его в своих HandlerInterceptors, и он отлично работает. Вот класс с ним и работает прямо сейчас на нескольких производственных сайтах: github.com/orubel/Beapi-API-Framework/blob/master/grails-app/ . Он отлично работал в Grails 2/3 и работает в Spring/Springboot HandlerInterceptors. - person Orubel; 14.06.2020