添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Describe the bug
We have our api gateway configured to use http2 (http2: server.http2.enabled= true)

  • spring-cloud: 2021.0.0
  • After upgrading to spring-cloud 2021.0.1 we get a netty protocol exception.
    Downgrading again to 2021.0.0 solves the problem.

    **Stacktrace**:
    [fullstacktrace.txt](https://github.com/spring-cloud/spring-cloud-gateway/files/8443260/stacktrace.txt)
    java.lang.IllegalArgumentException: Configured H2 protocol without TLS. Use H2 Clear-Text protocol via HttpClient#protocol or configure TLS via HttpClient#secure
    	at reactor.netty.http.client.HttpClientConnect$MonoHttpConnect.lambda$subscribe$0(HttpClientConnect.java:251) ~[reactor-netty-http-1.0.15.jar:1.0.15]
    	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
    Error has been observed at the following site(s):
    	*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.authe
    ntication.logout.LogoutWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
    	*__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    	*__checkpoint ⇢ HTTP POST "/api/xxxxx" [ExceptionHandlingWebHandler]
              

    Hi @mateofacu ,

    The problem lies in the HttpClientFactory; the create instance method contains the following code
    if (serverProperties.getHttp2().isEnabled()) { httpClient = httpClient.protocol(HttpProtocol.HTTP11, HttpProtocol.H2); }
    However, this causes problems when dealing with http connections or a mix of http and https connections. A simple workaround could be to make a HttpClientCustomizer that sets the protocols to a more sensible default
    httpClient = httpClient.protocol(HttpProtocol.HTTP11, HttpProtocol.H2, HttpProtocol.H2C)
    or the specific protocols for your connections

    Hi @DennieBroucke ,

    I didn't know about HttpClientCustomizer interface. I gave it a try but unfortunately we are still getting the same error.
    I checked that the httpClient was correctly configured using HttpProtocol.HTTP11, HttpProtocol.H2, HttpProtocol.H2C.

    The internal routes are "http". The services are using h2 enabled feature. I try the same test using http 1.1 but still I get the same error.

    I added a full stack trace.

    Any ideas are welcome.

    I verified that spring-cloud-gateway-server 3.1.0 code has the same default protocol configuration than 3.1.1.

    In NettyConfiguration

    if (serverProperties.getHttp2().isEnabled()) { httpClient = httpClient.protocol(HttpProtocol.HTTP11, HttpProtocol.H2); }

    Apologies for giving you false hope, we had some success, but after checking I've noticed we then had some other issues and reverted to a previous version of spring cloud as well.

    Any help is welcome. I realized HttpClient creation has been refactored in version 3.1.1. May be there is a configuration difference between both versions.

    Here are details for this issue:

  • by default spring cloud gateway enables 2 protocols HTTP11 & H2
  • H2 is not supported for HTTP protocol
  • underlining Reactor Netty is trying to remove H2 for configuration without SSL Context, but only in case sslProvider != null https://github.com/reactor/reactor-netty/blob/main/reactor-netty-http/src/main/java/reactor/netty/http/client/HttpClientConnect.java#L247
  • the previous version used "noop" SSL provider for H2
  • In the latest version this logic was removed and as a result Reactor Netty could not remove H2 and throws the exception https://github.com/reactor/reactor-netty/blob/main/reactor-netty-http/src/main/java/reactor/netty/http/client/HttpClientConnect.java#L253
  • In case you want to use spring cloud gateway to route to http, H2 should be disabled explicitly using server.http2.enabled=false because it will not be used anyway.

    Hi There!
    First of all, I would like to thank you all for your great work. I think, I could work around this issue by providing a custom HttpClientSslConfigurer bean replacing the one from the GatewayAutoConfiguration by marking the bean primary. In the #configureSsl method I did the following which seems to work:

     @Bean
      @Primary
      public HttpClientSslConfigurer noopHttpClientSslConfigurer(HttpClientProperties httpClientProperties,
          final ServerProperties serverProperties) {
        return new HttpClientSslConfigurer(httpClientProperties.getSsl(), serverProperties) {
          @Override
          public HttpClient configureSsl(HttpClient client) {
            if(serverProperties.getHttp2().isEnabled()) {
              HttpClientProperties.Ssl ssl = httpClientProperties.getSsl();
              return client.secure(sslContextSpec -> {
                Http2SslContextSpec clientSslCtxt = Http2SslContextSpec.forClient()
                    .configure(builder -> builder.trustManager(InsecureTrustManagerFactory.INSTANCE));
                sslContextSpec.sslContext(clientSslCtxt).handshakeTimeout(ssl.getHandshakeTimeout())
                    .closeNotifyFlushTimeout(ssl.getCloseNotifyFlushTimeout())
                    .closeNotifyReadTimeout(ssl.getCloseNotifyReadTimeout());
            return super.configureSsl(client);
    

    By doing this, we can still use HTTPS on the gateway and HTTP communication behind the gateway even if HTTP2 is active.

    Many wishes, Markus