Использование сжатия GZIP с Spring Boot / MVC / JavaConfig с RESTful

97

Мы используем Spring Boot / MVC с java-config на основе аннотаций для ряда RESTfulсервисов, и мы хотим выборочно включить HTTP GZIPсжатие потока для некоторых ответов API.

Я знаю, что могу сделать это вручную в своем контроллере и a byte[] @ResponseBody, однако мы предпочли бы полагаться на инфраструктуру SpringMVC (фильтры и т. Д.), Чтобы она автоматически выполняла преобразование и сжатие JSON (т.е. метод возвращает POJO).

Как я могу включить сжатие GZIP в ResponseBody или встроенном экземпляре Tomcat, и таким образом мы можем выборочно сжимать только некоторые ответы?

Благодарность!

PS: В настоящее время у нас нет конфигурации на основе XML.

user3182614
источник
Вам следует проверить GzipFilter .
aboutiblue
2
не используйте сжатие HTTP с HTTPS, если вы не знаете, что делаете
Нил МакГиган,

Ответы:

191

Остальные ответы устарели и / или чрезмерно сложны для чего-то, что должно быть простым IMO (как долго gzip существует? Дольше, чем Java ...) Из документов:

В application.properties 1.3+

# 🗜️🗜️🗜️
server.compression.enabled=true
# opt in to content types
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
# not worth the CPU cycles at some point, probably
server.compression.min-response-size=10240 

В application.properties 1.2.2 - <1.3

server.tomcat.compression=on
server.tomcat.compressableMimeTypes=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css

Старше 1.2.2:

@Component
public class TomcatCustomizer implements TomcatConnectorCustomizer {

  @Override
  public void customize(Connector connector) {
    connector.setProperty("compression", "on");
    // Add json and xml mime types, as they're not in the mimetype list by default
    connector.setProperty("compressableMimeType", "text/html,text/xml,text/plain,application/json,application/xml");
  }
}

Также обратите внимание, что это будет работать ТОЛЬКО, если вы используете встроенный tomcat:

Если вы планируете развертывать на невстроенном tomcat, вам нужно будет включить его в server.xml http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Standard_Implementation

Примечание по производству IRL:

Также, чтобы избежать всего этого, рассмотрите возможность использования настройки прокси / балансировщика нагрузки перед Tomcat с nginx и / или haproxy или аналогичными, поскольку он будет обрабатывать статические активы и gzip НАМНОГО более эффективно и легко, чем модель потоков Java / Tomcat.

Вы не хотите бросать кошку в ванну, потому что она занята сжатием вещей вместо обслуживания запросов (или, что более вероятно, раскручивает потоки / ест ЦП / кучу, сидя без дела в ожидании ввода-вывода базы данных, пока вы оплачиваете свой счет AWS, который почему традиционный Java / Tomcat может быть не очень хорошей идеей для начала в зависимости от того, что вы делаете, но я отвлекся ...)

ссылки: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#how-to-enable-http-response-compression

https://github.com/spring-projects/spring-boot/issues/2031

Джон Калвинер
источник
Ваш подход для версий старше 1.2.2 не будет работать, поскольку Spring Boot не ищет TomcatConnectorCustomizerэкземпляры в контексте приложения; они должны быть программно зарегистрированы сTomcatEmbeddedServletContainerFactory
Энди Уилкинсон
Спасибо за внимание. В итоге я отказался от этого, поскольку кажется, что загрузка static / dynamic / tomcat / vs все еще была проблемой. Это намного сложнее, чем должно быть ... Обратный прокси Nginx FTW!
Джон Калвинер,
3
В SpringBoot новыми свойствами являются server.compression.enabled = true и server.compression.mime-types = XXX, YYY github.com/spring-projects/spring-boot/wiki/…
blacelle
2
Если для весенней загрузки у нас есть несколько контроллеров отдыха, все возвращающие ответы JSON. Можем ли мы выборочно применить zip на некоторых контроллерах?
3
Вы также должны указать минимальный размер ответа для сжатия (например, 10 КБ), в противном случае сервер будет вынужден сжимать каждый запрос (например, 0,5 КБ). server.compression.min-response-size=10240
UsamaAmjad
13

По последним версиям в application.ymlconfig:

---

spring:
  profiles: dev

server:
  compression:
    enabled: true
    mime-types: text/html,text/css,application/javascript,application/json

---
М. Реза Насирлоо
источник
Соответствующий отчет об ошибке и исправление, в котором это было изменено: github.com/spring-projects/spring-boot/issues/2737
McLovin
12

По сути, это то же решение, что и @andy-wilkinson, но начиная с Spring Boot 1.0 метод customize (...) имеет параметр ConfigurableEmbeddedServletContainer .

Другое дело , что стоит упомянуть, что Tomcat только сжимает типы содержимого из text/html, text/xmlи text/plainпо умолчанию. Ниже приведен пример, который также поддерживает сжатие application/json:

@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer servletContainer) {
            ((TomcatEmbeddedServletContainerFactory) servletContainer).addConnectorCustomizers(
                    new TomcatConnectorCustomizer() {
                        @Override
                        public void customize(Connector connector) {
                            AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
                            httpProtocol.setCompression("on");
                            httpProtocol.setCompressionMinSize(256);
                            String mimeTypes = httpProtocol.getCompressableMimeTypes();
                            String mimeTypesWithJson = mimeTypes + "," + MediaType.APPLICATION_JSON_VALUE;
                            httpProtocol.setCompressableMimeTypes(mimeTypesWithJson);
                        }
                    }
            );
        }
    };
}
Мацев
источник
Я попытался добавить это в свою конфигурацию Java и обнаружил, что сжатие вообще не работает. Я использую Spring Boot с Tomcat в качестве встроенного контейнера и поинтересовался, есть ли какие-то дополнительные вещи, которые мне нужно установить, кроме этой конфигурации?
Michael Coxon
2
Попробуйте проверить, указав Accept-Encoding: gzip,deflateзаголовок, если вы используете curl:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
matsev
9

Spring Boot 1.4 Используйте это для всех сжатий Javascript HTML Json.

server.compression.enabled: true
server.compression.mime-types: application/json,application/xml,text/html,text/xml,text/plain,text/css,application/javascript
Ронни Шибли
источник
Как мы проверяем это сжатие?
Bhargav
@Bhargav См. Заголовок вашего ответа api. Он должен содержать заголовок: Content-Encoding:gzip
Sumit ПВД
6

Добавление GZip в Tomcat не работает в моем проекте Spring Boot. Я использовал найденный здесь CompressingFilter .

@Bean
public Filter compressingFilter() {
    CompressingFilter compressingFilter = new CompressingFilter();
    return compressingFilter;
}
user1127860
источник
@ user1127860 tnx это работает, но как бы настроить этот фильтр дальше? Я использую весеннюю загрузку и, похоже, не могу добавить параметры инициализации, как указано в руководстве в web.xml
весна
5

Чтобы включить сжатие GZIP, вам необходимо изменить конфигурацию встроенного экземпляра Tomcat. Для этого вы объявляете EmbeddedServletContainerCustomizerbean-компонент в конфигурации Java, а затем регистрируете в TomcatConnectorCustomizerнем.

Например:

@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainerFactory factory) {
            ((TomcatEmbeddedServletContainerFactory) factory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
                @Override
                public void customize(Connector connector) {
                    AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
                    httpProtocol.setCompression("on");
                    httpProtocol.setCompressionMinSize(64);
                }
            });
        }
    };
}

См. Документацию Tomcat для получения дополнительных сведений о различных доступных параметрах конфигурации сжатия.

Вы говорите, что хотите выборочно включить сжатие. В зависимости от ваших критериев выбора может быть достаточно описанного выше подхода. Он позволяет вам контролировать сжатие с помощью пользовательского агента запроса, размера ответа и типа mime ответа.

Если это не соответствует вашим потребностям, я считаю, что вам придется выполнить сжатие в своем контроллере и вернуть ответ byte [] с заголовком кодирования содержимого gzip.

Энди Уилкинсон
источник
1
В чем разница между вашим ответом на вариант установки параметра application.properties? server.compression.enabled = true server.compression.mime-types = application / json, application / xml, text / html, text / xml, text / plain, application / javascript, text / css
lukass77
Этот ответ был написан до того, как была доступна конфигурация сжатия на основе свойств. Они эквивалентны, но подход на основе свойств проще, поэтому я бы рекомендовал его использовать.
Энди Уилкинсон
просто хочу поделиться тем, что в моем случае tomcat находится за балансировщиком нагрузки, который получает https и передает запрос на tomcat как http., когда я использую решение application.properties, ответ не gzip, но когда я использую программное решение для конфигурации на соединителе, я получаю gzip-ответ с https-запросом LB
lukass77
другой вопрос, если я использую решение application.properties .. и определяю еще 2 разъема на портах 8081 и 8082 .. применяется ли сжатие ко всем разъемам или только к разъему 8080?
lukass77
Я проверяю это, сжатие применяется только к порту 8080, даже если вы откроете больше разъемов .., я думаю, что ошибка должна быть открыта для этой весенней загрузки ?? .., поэтому единственным рабочим решением для меня была программная конфигурация для каждого разъема, не application.properties
lukass77
0

У меня была такая же проблема в моем проекте Spring Boot + Spring Data при вызове файла @RepositoryRestResource.

Проблема в возвращаемом MIME-типе; что есть application/hal+json. Добавление его к server.compression.mime-typesсобственности решило эту проблему для меня.

Надеюсь, это поможет кому-то другому!

Сержиньо
источник