Usando compresión GZIP con Spring Boot / MVC / JavaConfig con RESTful


96

Usamos Spring Boot / MVC con java-config basado en anotaciones para series de RESTfulservicios y queremos habilitar selectivamente la HTTP GZIPcompresión de transmisión en algunas respuestas API.

Sé que puedo hacer esto manualmente en mi controlador y byte[] @ResponseBody, sin embargo, preferiríamos confiar en la infraestructura SpringMVC (filtros / etc.) y hacer que automáticamente haga la conversión y compresión JSON (es decir, el método devuelve un POJO).

¿Cómo puedo habilitar la compresión GZIP en ResponseBody o en la instancia incrustada de Tomcat, y de alguna manera podemos comprimir selectivamente solo algunas respuestas?

¡Gracias!

PD: Actualmente no tenemos ninguna configuración basada en XML.


Debería consultar GzipFilter .
aproximadamente azul

2
no use la compresión HTTP con HTTPS a menos que sepa lo que está haciendo
Neil McGuigan

Respuestas:


189

El resto de estas respuestas están desactualizadas y / o son demasiado complicadas para algo que debería ser simple IMO (¿cuánto tiempo ha existido gzip por ahora? Más que Java ...) De los documentos:

En 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 

En 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

Mayor que 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");
  }
}

También tenga en cuenta que esto SOLO funcionará si está ejecutando tomcat integrado:

Si planea implementar en un Tomcat no integrado, tendrá que habilitarlo en server.xml http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Standard_Implementation

Nota de producción de IRL:

Además, para evitar todo esto, considere usar una configuración de balanceador de carga / proxy frente a Tomcat con nginx y / o haproxy o similar, ya que manejará activos estáticos y gzip MUCHO más eficiente y fácilmente que el modelo de subprocesos de Java / Tomcat.

No quiere tirar al gato al baño porque está ocupado comprimiendo cosas en lugar de atender solicitudes (o más probablemente girando subprocesos / comiendo CPU / montón esperando que ocurra la E / S de la base de datos mientras se ejecuta su factura de AWS, que es por qué Java / Tomcat tradicional podría no ser una buena idea para empezar dependiendo de lo que esté haciendo, pero estoy divagando ...)

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


Su enfoque para versiones anteriores a la 1.2.2 no funcionará ya que Spring Boot no busca TomcatConnectorCustomizerinstancias en el contexto de la aplicación; Tienen que estar inscrito en programáticamenteTomcatEmbeddedServletContainerFactory
Andy Wilkinson

Gracias por el aviso. Terminé renunciando a esto porque parece que el arranque estático / dinámico / tomcat / vs seguía siendo un problema. Esto es mucho más difícil de lo que debería ser ... Nginx reverse proxy FTW!
John Culviner

3
En SpringBoot, las nuevas propiedades son server.compression.enabled = true y server.compression.mime-types = XXX, YYY github.com/spring-projects/spring-boot/wiki/…
blacelle

2
Si para el arranque de primavera tenemos varios controladores de descanso, todos devuelven respuestas JSON. ¿Podemos aplicar selectivamente el zip en algunos controladores?

3
También debe mencionar el tamaño mínimo de respuesta para la compresión (p. Ej., 10 KB); de lo contrario, el servidor debe sobrecargar cada solicitud (p. Ej., 0,5 KB). server.compression.min-response-size=10240
UsamaAmjad


12

Esta es básicamente la misma solución que @ andy-wilkinson proporcionó, pero a partir de Spring Boot 1.0, el método personalizar (...) tiene un parámetro ConfigurableEmbeddedServletContainer .

Otra cosa que vale la pena mencionar es que Tomcat solo comprime los tipos de contenido de text/html, text/xmly text/plainde forma predeterminada. A continuación, se muestra un ejemplo que también admite la compresión 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);
                        }
                    }
            );
        }
    };
}

Intenté agregar esto a mi configuración de Java y descubrí que la compresión no parecía estar funcionando en absoluto. Estoy usando Spring Boot con Tomcat como contenedor integrado, y me preguntaba si había algo adicional que necesitaba establecer además de esta configuración.
Michael Coxon

2
Intente verificar especificando el Accept-Encoding: gzip,deflateencabezado, si está usando curl:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
matsev

9

Spring Boot 1.4 Use esto para Javascript HTML Json todas las compresiones.

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

¿Cómo verificamos esta compresión?
Bhargav

@Bhargav Vea el encabezado de respuesta de su respuesta de API. Debe contener el encabezado: Content-Encoding:gzip
Sumit Jha


6

Enabeling GZip en Tomcat no funcionó en mi Spring Boot Project. Usé CompressingFilter que se encuentra aquí .

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

@ user1127860 tnx esto funciona, pero de todos modos, ¿configurar este filtro más? Uso el arranque de primavera y parece que no puedo agregar parámetros de inicio como dice el manual en web.xml
Primavera de

5

Para habilitar la compresión GZIP, debe modificar la configuración de la instancia de Tomcat incorporada. Para hacerlo, declare un EmbeddedServletContainerCustomizerbean en su configuración de Java y luego registre unTomcatConnectorCustomizer con él.

Por ejemplo:

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

Consulte la documentación de Tomcat para obtener más detalles sobre las diversas opciones de configuración de compresión que están disponibles.

Dice que desea habilitar selectivamente la compresión. Dependiendo de sus criterios de selección, el enfoque anterior puede ser suficiente. Le permite controlar la compresión por el agente de usuario de la solicitud, el tamaño de la respuesta y el tipo de mímica de la respuesta.

Si esto no satisface sus necesidades, creo que tendrá que realizar la compresión en su controlador y devolver una respuesta de byte [] con un encabezado de codificación de contenido gzip.


1
¿Cuál es la diferencia entre su respuesta a la opción de poner la configuración en 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

Esta respuesta se escribió antes de que estuviera disponible la configuración de compresión basada en propiedades. Son equivalentes, pero el enfoque basado en propiedades es más fácil, por lo que recomendaría usarlo.
Andy Wilkinson

solo quiero compartir que, en mi caso, tomcat está detrás de un equilibrador de carga que obtiene https y reenvía la solicitud a tomcat como http., cuando uso la respuesta de la solución application.properties no es gzip, pero cuando uso la solución de configuración programática en el conector obtengo respuesta gzip con solicitud https LB
lukass77

otra pregunta en caso de que use la solución application.properties .. y defino más 2 conectores en los puertos 8081 y 8082 .. ¿la compresión se aplica a todos los conectores o solo al conector 8080?
lukass77

Verifico esto, la competencia solo se aplica en el puerto 8080, incluso si abre más conectores ... creo que el error debería estar abierto en esto para el arranque de primavera ..., así que la única solución de trabajo para mí fue la configuración programática para cada conector, no application.properties
lukass77

0

Tuve el mismo problema en mi proyecto Spring Boot + Spring Data al invocar a @RepositoryRestResource.

El problema es el tipo MIME devuelto; que es application/hal+json. Agregarlo a la server.compression.mime-typespropiedad resolvió este problema para mí.

¡Espero que esto ayude a alguien más!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.