Utilisation de la compression GZIP avec Spring Boot / MVC / JavaConfig avec RESTful

96

Nous utilisons Spring Boot / MVC avec java-config basé sur des annotations pour une série de RESTfulservices et nous voulons activer sélectivement la HTTP GZIPcompression de flux sur certaines réponses d'API.

Je sais que je peux le faire manuellement dans mon contrôleur et un byte[] @ResponseBody, mais nous préférerions nous fier à l'infrastructure SpringMVC (filtres / etc) et lui faire faire automatiquement la conversion et la compression JSON (c'est-à-dire que la méthode renvoie un POJO).

Comment puis-je activer la compression GZIP dans ResponseBody ou l'instance Tomcat intégrée, et d'une manière que nous pouvons compresser de manière sélective uniquement certaines réponses?

Merci!

PS: Nous n'avons actuellement aucune configuration basée sur XML.

user3182614
la source
Vous devriez vérifier GzipFilter .
approxiblue
2
n'utilisez pas la compression HTTP avec HTTPS sauf si vous savez ce que vous faites
Neil McGuigan

Réponses:

189

Le reste de ces réponses est obsolète et / ou trop compliqué pour quelque chose qui devrait être simple IMO (depuis combien de temps gzip existe-t-il? Plus longtemps que Java ...)

Dans 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 

Dans 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

Plus de 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");
  }
}

Notez également que cela fonctionnera UNIQUEMENT si vous exécutez Tomcat intégré:

Si vous prévoyez de déployer sur un tomcat non intégré, vous devrez l'activer dans server.xml http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Standard_Implementation

Note de production IRL:

Aussi, pour éviter tout cela, envisagez d'utiliser une configuration de proxy / équilibreur de charge devant Tomcat avec nginx et / ou haproxy ou similaire, car il gérera les actifs statiques et gzip BEAUCOUP plus efficacement et plus facilement que le modèle de thread de Java / Tomcat.

Vous ne voulez pas jeter `` chat dans le bain parce qu'il est occupé à compresser des choses au lieu de servir des demandes (ou plus probablement à faire tourner des threads / à manger du processeur / du tas en attendant que l'E / S de la base de données se produise lors de l'exécution de votre facture AWS qui est pourquoi Java / Tomcat traditionnel n'est peut-être pas une bonne idée pour commencer en fonction de ce que vous faites mais je m'égare ...)

réfs: 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

John Culviner
la source
Votre approche pour les versions antérieures à 1.2.2 ne fonctionnera pas car Spring Boot ne recherche pas d' TomcatConnectorCustomizerinstances dans le contexte de l'application; ils doivent être enregistrés par programme avecTomcatEmbeddedServletContainerFactory
Andy Wilkinson
Merci pour l'information. J'ai fini par abandonner cela car il semble que le démarrage statique / dynamique / tomcat / vs était toujours un problème. C'est bien plus difficile qu'il ne devrait l'être ... Proxy inverse Nginx FTW!
John Culviner
3
Dans SpringBoot, les nouvelles propriétés sont server.compression.enabled = true et server.compression.mime-types = XXX, YYY github.com/spring-projects/spring-boot/wiki/…
blacelle
2
Si pour le démarrage du printemps, nous avons plusieurs contrôleurs de repos retournant tous des réponses JSON. Pouvons-nous appliquer sélectivement le zip sur certains contrôleurs?
3
Vous devez également mentionner la taille de réponse minimale pour la compression (ex: 10 Ko), sinon cela devient une surcharge pour le serveur de compresser chaque demande (ex: 0,5 Ko). server.compression.min-response-size=10240
UsamaAmjad
13

Sur les versions récentes de la application.ymlconfiguration:

---

spring:
  profiles: dev

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

---
M. Reza Nasirloo
la source
Le rapport de bogue correspondant et le correctif où cela a été modifié sont github.com/spring-projects/spring-boot/issues/2737
McLovin
12

C'est fondamentalement la même solution que @ andy-wilkinson fournie, mais à partir de Spring Boot 1.0, la méthode de personnalisation (...) a un paramètre ConfigurableEmbeddedServletContainer .

Une autre chose qui est utile de mentionner que Tomcat ne compresse que les types de contenu de text/html, text/xmlet text/plainpar défaut. Voici un exemple qui prend également en charge la compression de 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);
                        }
                    }
            );
        }
    };
}
matsev
la source
J'ai essayé de l'ajouter dans ma configuration Java et j'ai trouvé que la compression ne semblait pas fonctionner du tout. J'utilise Spring Boot avec Tomcat comme conteneur intégré et je me suis demandé s'il y avait des choses supplémentaires que je devais définir autres que cette configuration?
Michael Coxon
2
Essayez de vérifier en spécifiant l'en- Accept-Encoding: gzip,deflatetête, si vous utilisez curl:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
matsev
9

Spring Boot 1.4 Utilisez ceci pour Javascript HTML Json toutes les compressions.

server.compression.enabled: true
server.compression.mime-types: application/json,application/xml,text/html,text/xml,text/plain,text/css,application/javascript
Ronny Shibley
la source
Comment vérifier cette compression?
Bhargav
@Bhargav Voir l'en-tête de réponse de votre réponse API. Il doit contenir l' en- tête: Content-Encoding:gzip
Sumit Jha
6

L'activation de GZip dans Tomcat ne fonctionne pas dans mon projet Spring Boot. J'ai utilisé CompressingFilter trouvé ici .

@Bean
public Filter compressingFilter() {
    CompressingFilter compressingFilter = new CompressingFilter();
    return compressingFilter;
}
user1127860
la source
@ user1127860 tnx cela fonctionne mais de toute façon pour configurer ce filtre plus loin? J'utilise Spring Boot et je n'arrive pas à ajouter des paramètres init comme le dit le manuel dans web.xml
Spring
5

Pour activer la compression GZIP, vous devez modifier la configuration de l'instance Tomcat intégrée. Pour ce faire, vous déclarez un EmbeddedServletContainerCustomizerbean dans votre configuration Java puis enregistrez un TomcatConnectorCustomizeravec lui.

Par exemple:

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

Consultez la documentation Tomcat pour plus de détails sur les différentes options de configuration de compression disponibles.

Vous dites que vous souhaitez activer sélectivement la compression. Selon vos critères de sélection, alors l'approche ci-dessus peut être suffisante. Il vous permet de contrôler la compression par l'agent utilisateur de la requête, la taille de la réponse et le type mime de la réponse.

Si cela ne répond pas à vos besoins, je crois que vous devrez effectuer la compression dans votre contrôleur et renvoyer une réponse byte [] avec un en-tête de codage de contenu gzip.

Andy Wilkinson
la source
1
quelle est la différence entre votre réponse à l'option de mettre le paramètre sur 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
Cette réponse a été écrite avant que la configuration de compression basée sur les propriétés ne soit disponible. Ils sont équivalents, mais l'approche basée sur les propriétés est plus facile, je recommanderais donc de l'utiliser.
Andy Wilkinson
je veux juste partager que dans mon cas, tomcat est derrière un équilibreur de charge qui obtient https et transmet la demande à tomcat en tant que http., lorsque j'utilise la solution application.properties, la réponse n'est pas gzip mais lorsque j'utilise la solution de configuration programmatique sur le connecteur, je reçois Réponse gzip avec requête https LB
lukass77
une autre question au cas où j'utiliserais la solution application.properties .. et définirais plus de 2 connecteurs sur les ports 8081 et 8082 .. la compression s'applique-t-elle à tous les connecteurs ou simplement au connecteur 8080?
lukass77
Je le vérifie, la compersion ne s'applique que sur le port 8080, même si vous ouvrez plus de connecteurs .., je pense que le bogue devrait être ouvert à ce sujet au démarrage à ressort ?? .., donc la seule solution de travail pour moi était la configuration programmatique pour chaque connecteur, not application.properties
lukass77
0

J'ai eu le même problème dans mon projet Spring Boot + Spring Data lors de l'appel à un fichier @RepositoryRestResource.

Le problème est le type MIME renvoyé; qui est application/hal+json. L'ajouter à la server.compression.mime-typespropriété a résolu ce problème pour moi.

J'espère que cela aide quelqu'un d'autre!

Serginho
la source