Використання стиснення GZIP з Spring Boot / MVC / JavaConfig з RESTful


96

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

Я знаю, що можу зробити це вручну у своєму контролері та a byte[] @ResponseBody, однак ми воліли б покластись на інфраструктуру SpringMVC (фільтри / і т.д.) і забезпечити її автоматичне перетворення та стиснення JSON (тобто метод повертає POJO).

Як я можу ввімкнути стиснення GZIP у екземплярі ResponseBody або вбудованому Tomcat, і таким чином ми можемо вибірково стискати лише деякі відповіді?

Дякую!

PS: На даний момент у нас немає конфігурації на основі XML.


Вам слід перевірити GzipFilter .
approxiblue

2
не використовуйте стиснення HTTP з HTTPS, якщо ви не знаєте, що робите
Ніл Макгіган

Відповіді:


189

Решта цих відповідей застаріли та / або вгорі ускладнені для чогось, що повинно бути простим IMO (як довго gzip існує зараз? Довше, ніж Java ...) З документації:

У застосуванні. Властивості 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 

У застосуванні. Властивості 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.

Ви не хочете кидати "кота у ванну, тому що він зайнятий стисненням речей замість того, щоб обслуговувати запити (або, швидше за все, обертає нитки / їсть процесор / купу, сидячи навколо, чекаючи введення IO бази даних під час запуску вашого рахунку 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
Енді Уілкінсон

Дякую за голови. У підсумку я відмовився від цього, оскільки, здається, статичний / динамічний / 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


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 Перегляньте заголовок відповіді вашої відповіді api. Він повинен містити заголовок: Content-Encoding:gzip
Sumit ПВД


6

Позначення GZip у Tomcat не спрацювало у моєму проекті Spring Boot. Я використовував CompressingFilter, знайдений тут .

@Bean
public Filter compressingFilter() {
    CompressingFilter compressingFilter = new CompressingFilter();
    return compressingFilter;
}

@ user1127860 tnx це працює, але в будь-якому випадку для подальшого налаштування цього фільтра? Я використовую весняне завантаження, і, здається, не можу додати параметри ініціалізації, як сказано в інструкції в web.xml
Весна

5

Щоб увімкнути стиснення GZIP, вам потрібно змінити конфігурацію вбудованого екземпляра Tomcat. Для цього ви заявляєте EmbeddedServletContainerCustomizerbean у своїй конфігурації Java, а потім реєструєте в TomcatConnectorCustomizerньому a .

Наприклад:

@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 відповіді.

Якщо це не відповідає вашим потребам, тоді, я вважаю, вам доведеться виконати стиснення в контролері та повернути байтову [] відповідь із заголовком кодування вмісту 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, навіть якщо ви відкриваєте більше роз'ємів .., я думаю, що помилка повинна бути відкрита на цьому для весняного завантаження ?? .., тому єдиним робочим рішенням для мене була програмна конфігурація для кожного роз'єму, не застосовується.
властивості

0

У мене була та ж проблема у моєму проекті Spring Boot + Spring Data при зверненні до @RepositoryRestResource.

Проблема полягає у поверненні типу MIME; який є application/hal+json. Додавання його до server.compression.mime-typesвластивості вирішило цю проблему для мене.

Сподіваюся, це допомагає комусь іншому!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.