web-dev-qa-db-fra.com

Activer http2 avec Tomcat dans Spring Boot

Tomcat 8.5, qui sera la valeur par défaut dans Spring Boot 1.4, (à paraître demain) prend en charge http2.

Comment puis http2 être activé dans un Spring Boot demande?

34
yglodt

La façon la plus élégante et la plus performante d'activer HTTP/2 avec une application Spring Boot suit ici.

Tout d'abord, comme mentionné dans la réponse d'Andy Wilkinson, vous devez activer HTTP/2 au niveau de Tomcat:

@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
    return (container) -> {
        if (container instanceof TomcatEmbeddedServletContainerFactory) {
            ((TomcatEmbeddedServletContainerFactory) container)
                    .addConnectorCustomizers((connector) -> {
                connector.addUpgradeProtocol(new Http2Protocol());
            });
        }
    };
}

Si vous n'utilisez pas de Tomcat intégré, vous pouvez configurer l'écoute HTTP/2 comme ceci:

<Connector port="5080" protocol="HTTP/1.1" connectionTimeout="20000">
    <UpgradeProtocol className="org.Apache.coyote.http2.Http2Protocol" />
</Connector>

N'oubliez pas que vous avez besoin de Tomcat> = 8.5.

Ensuite, vous devez utiliser HAProxy (version> = 1.7) devant Tomcat pour vous occuper du chiffrement.

Le client parlera https à HAProxy et HAProxy parlera en clair HTTP/1.1 ou HTTP/2 au backend, comme le client l'a demandé. Il n'y aura aucune traduction de protocole inutile.

La configuration HAProxy correspondante est ici:

# Create PEM: cat cert.crt cert.key ca.crt > /etc/ssl/certs/cert.pem

global
    tune.ssl.default-dh-param 2048
    ssl-default-bind-options no-sslv3 no-tls-tickets force-tlsv12
    ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
    chroot /var/lib/haproxy
    user haproxy
    group haproxy

defaults
    timeout connect 10000ms
    timeout client 60000ms
    timeout server 60000ms

frontend fe_https
    mode tcp
    rspadd Strict-Transport-Security:\ max-age=31536000;\ includeSubDomains;\ preload
    rspadd X-Frame-Options:\ DENY
    bind *:443 ssl crt /etc/ssl/certs/cert.pem alpn h2,http/1.1
    default_backend be_http

backend be_http
    mode tcp
    server domain 127.0.0.1:8080
    # compression algo gzip # does not work in mode "tcp"
    # compression type text/html text/css text/javascript application/json

Modifier 2019

Je fais face à deux problèmes lors de l'utilisation du mode "tcp"

  • La compression ne fonctionne pas, car elle dépend du mode http. Donc le backend doit s'en occuper
  • Le backend ne peut pas voir l'adresse IP du client. J'ai probablement besoin de NAT. Enquêtes toujours ...

En règle générale, étant donné que les serveurs proxy proxy utilisent une connexion TCP de niveau inférieur, il n'y a pas d'accès à des éléments http

17
yglodt

Vous devez ajouter le protocole de mise à niveau HTTP 2 au connecteur de Tomcat. Vous pouvez le faire en personnalisant le conteneur Tomcat intégré:

Java 8:

@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
    return (container) -> {
        if (container instanceof TomcatEmbeddedServletContainerFactory) {
            ((TomcatEmbeddedServletContainerFactory) container)
                    .addConnectorCustomizers((connector) -> {
                connector.addUpgradeProtocol(new Http2Protocol());
            });
        }
    };
}

Java 7:

@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
    return new EmbeddedServletContainerCustomizer() {

        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (container instanceof TomcatEmbeddedServletContainerFactory) {
                ((TomcatEmbeddedServletContainerFactory) container)
                        .addConnectorCustomizers(new TomcatConnectorCustomizer() {
                    @Override
                    public void customize(Connector connector) {
                        connector.addUpgradeProtocol(new Http2Protocol());
                    }

                });
            }
        }

    };
}
29
Andy Wilkinson

Dans Spring Boot 2.1 et supérieur, c'est aussi simple que d'ajouter cette propriété à votre fichier .properties (ou .yml):

server.http2.enabled=true

Vous pouvez également le faire par programme comme ceci (dans l'une de vos classes de configuration):

@Bean
public ConfigurableServletWebServerFactory tomcatCustomizer() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addConnectorCustomizers(connector -> connector.addUpgradeProtocol(new Http2Protocol()));
    return factory;
}
17
Mahozad

Dans Spring Boot 2, vous avez d'abord besoin d'un certificat - il peut être généré comme ceci:

keytool -genkey -keyalg RSA -alias my-the-best-api -keystore c:\tmp\keystore.store -storepass secret -validity 3650 -keysize 2048

Ensuite, il vous suffit d'ajouter ce certificat à classpath et d'ajouter les propriétés nécessaires à application.properties:

server.http2.enabled=true
server.port = 8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-password=secret
9
Jozef Najman