Utilizzo della compressione GZIP con Spring Boot / MVC / JavaConfig con RESTful


95

Usiamo Spring Boot / MVC con java-config basato su annotazioni per una serie di RESTfulservizi e vogliamo abilitare selettivamente la HTTP GZIPcompressione del flusso su alcune risposte API.

So di poterlo fare manualmente nel mio controller e a byte[] @ResponseBody, tuttavia preferiremmo fare affidamento sull'infrastruttura SpringMVC (filtri / ecc.) E fare in modo che esegua automaticamente la conversione e la compressione JSON (cioè il metodo restituisce un POJO).

Come posso abilitare la compressione GZIP nell'istanza ResponseBody o Tomcat incorporata e in un modo possiamo comprimere selettivamente solo alcune risposte?

Grazie!

PS .: Al momento non abbiamo alcuna configurazione basata su XML.


Dovresti controllare GzipFilter .
— approxiblue

2
non utilizzare la compressione HTTP con HTTPS a meno che tu non sappia cosa stai facendo
— Neil McGuigan

Risposte:


188

Il resto di queste risposte sono obsolete e / o esageratamente complicate per qualcosa che dovrebbe essere semplice IMO (da quanto tempo gzip è in circolazione? Più lungo di Java ...) Dai documenti:

In 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 

In 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

Più vecchio di 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");
  }
}

Nota anche che funzionerà SOLO se stai eseguendo tomcat incorporato:

Se prevedi di eseguire la distribuzione su un tomcat non incorporato, dovrai abilitarlo in server.xml http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Standard_Implementation

Nota di produzione IRL:

Inoltre, per evitare tutto ciò, considera l'utilizzo di una configurazione proxy / bilanciatore del carico davanti a Tomcat con nginx e / o haproxy o simili poiché gestirà risorse statiche e gzip MOLTO in modo più efficiente e semplice rispetto al modello di threading di Java / Tomcat.

Non vuoi gettare il gatto nella vasca da bagno perché è impegnato a comprimere cose invece di servire le richieste (o più probabilmente a far girare thread / mangiare CPU / heap in attesa che si verifichi l'IO del database durante l'esecuzione della tua fattura AWS che è perché il tradizionale Java / Tomcat potrebbe non essere una buona idea per cominciare a seconda di quello che stai facendo, ma sto divagando ...)

rif: 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


Il tuo approccio per le versioni precedenti alla 1.2.2 non funzionerà poiché Spring Boot non cerca le TomcatConnectorCustomizeristanze nel contesto dell'applicazione; devono essere registrati programmaticamente conTomcatEmbeddedServletContainerFactory
— Andy Wilkinson

Grazie per il testa a testa. Ho finito per rinunciare a questo dato che sembra che static / dynamic / tomcat / vs boot fosse ancora un problema. Questo è molto più difficile di quanto dovrebbe essere ... Proxy inverso Nginx FTW!
— John Culviner

3
In SpringBoot, le nuove proprietà sono server.compression.enabled = true e server.compression.mime-types = XXX, YYY github.com/spring-projects/spring-boot/wiki/…
— blacelle

2
Se per l'avvio primaverile abbiamo più controller di riposo che restituiscono tutti risposte JSON. Possiamo applicare selettivamente lo zip su alcuni controller?

3
Dovresti anche menzionare la dimensione minima della risposta per la compressione (es: 10KB) altrimenti diventa sovraccarico per il server comprimere ogni richiesta (es: 0,5KB). server.compression.min-response-size=10240
— UsamaAmjad


12

Questa è fondamentalmente la stessa soluzione fornita da @ andy-wilkinson, ma a partire da Spring Boot 1.0 il metodo personalizza (...) ha un parametro ConfigurableEmbeddedServletContainer .

Un'altra cosa che è degno di nota è che Tomcat comprime solo i tipi di contenuto di text/html, text/xmle text/plainper impostazione predefinita. Di seguito è riportato un esempio che supporta anche la compressione di 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);
                        }
                    }
            );
        }
    };
}

Ho provato ad aggiungerlo alla mia configurazione Java e ho scoperto che la compressione non sembrava funzionare affatto. Sto usando Spring Boot con Tomcat come contenitore incorporato e mi chiedevo se ci fossero altre cose che dovevo impostare oltre a questa configurazione?
— Michael Coxon

2
Prova a verificare specificando l' Accept-Encoding: gzip,deflateintestazione, se stai usando curl:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
— matsev

9

Spring Boot 1.4 Usa questo per Javascript HTML Json tutte le compressioni.

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

Come verifichiamo questa compressione?
— Bhargav

@Bhargav Vedi l'intestazione della risposta della tua risposta API. Dovrebbe contenere l'intestazione: Content-Encoding:gzip
— Sumit Jha


6

L'abilitazione di GZip in Tomcat non ha funzionato nel mio progetto Spring Boot. Ho usato CompressingFilter trovato qui .

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

@ user1127860 tnx funziona ma comunque per configurare ulteriormente questo filtro? Uso lo spring boot e non riesco ad aggiungere i parametri di inizializzazione come dice il manuale in web.xml
— Primavera

5

Per abilitare la compressione GZIP, è necessario modificare la configurazione dell'istanza Tomcat incorporata. Per fare ciò, dichiari un EmbeddedServletContainerCustomizerbean nella tua configurazione Java e quindi registri un TomcatConnectorCustomizercon esso.

Per esempio:

@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);
                }
            });
        }
    };
}

Consultare la documentazione di Tomcat per ulteriori dettagli sulle varie opzioni di configurazione della compressione disponibili.

Dici di voler abilitare selettivamente la compressione. A seconda dei criteri di selezione, l'approccio di cui sopra potrebbe essere sufficiente. Ti consente di controllare la compressione da parte dello user-agent della richiesta, la dimensione della risposta e il tipo MIME della risposta.

Se questo non soddisfa le tue esigenze, credo che dovrai eseguire la compressione nel tuo controller e restituire una risposta byte [] con un'intestazione di codifica del contenuto gzip.


1
qual è la differenza tra la tua risposta all'opzione di mettere l'impostazione su 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

Questa risposta è stata scritta prima che fosse disponibile la configurazione della compressione basata sulle proprietà. Sono equivalenti, ma l'approccio basato sulle proprietà è più semplice, quindi consiglierei di usarlo.
— Andy Wilkinson

voglio solo condividere che nel mio caso tomcat è dietro un bilanciatore del carico che ottiene https e forword la richiesta a tomcat come http., quando uso la risposta della soluzione application.properties non è gzip ma quando uso la soluzione di configurazione programmatica sul connettore ottengo risposta gzip con richiesta https LB
— lukass77

un'altra domanda nel caso in cui utilizzo la soluzione application.properties .. e definisco più 2 connettori sulle porte 8081 e 8082 .. la compressione si applica a tutti i connettori o solo al connettore 8080?
— lukass77

lo verifico, la compersione si applica solo alla porta 8080, anche se apri più connettori .., penso che il bug dovrebbe essere aperto su questo per l'avvio a molla ?? .., quindi l'unica soluzione di lavoro per me era la configurazione programmatica per ciascun connettore, not application.properties
— lukass77

0

Ho avuto lo stesso problema nel mio progetto Spring Boot + Spring Data quando ho invocato un file @RepositoryRestResource.

Il problema è il tipo MIME restituito; che è application/hal+json. L'aggiunta alla server.compression.mime-typesproprietà ha risolto questo problema per me.

Spero che questo aiuti a qualcun altro!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.