Embedded Web Servers

每个 Spring Boot Web 应用程序都包含一个嵌入式 Web 服务器。此功能导致了许多操作问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节将回答这些问题。

Each Spring Boot web application includes an embedded web server. This feature leads to a number of how-to questions, including how to change the embedded server and how to configure the embedded server. This section answers those questions.

Use Another Web Server

许多 Spring Boot starter 都包含默认的嵌入式容器。

Many Spring Boot starters include default embedded containers.

  • For servlet stack applications, the spring-boot-starter-web includes Tomcat by including spring-boot-starter-tomcat, but you can use spring-boot-starter-jetty or spring-boot-starter-undertow instead.

  • For reactive stack applications, the spring-boot-starter-webflux includes Reactor Netty by including spring-boot-starter-reactor-netty, but you can use spring-boot-starter-tomcat, spring-boot-starter-jetty, or spring-boot-starter-undertow instead.

切换至其他 HTTP 服务器时,你需要用自己需要的默认依赖项替换那些默认依赖项。Spring Boot 为每个受支持的 HTTP 服务器提供了一个单独的 starter,以帮助完成此过程。

When switching to a different HTTP server, you need to swap the default dependencies for those that you need instead. To help with this process, Spring Boot provides a separate starter for each of the supported HTTP servers.

以下 Maven 示例演示了如何排除 Tomcat 并添加 Jetty 以用于 Spring MVC:

The following Maven example shows how to exclude Tomcat and include Jetty for Spring MVC:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<!-- Exclude the Tomcat dependency -->
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

以下 Gradle 示例配置了必需的依赖项和一个 {url-gradle-docs}/resolution_rules.html#sec:module_replacement[模块替换] 以便使用 Undertow 替换 Reactor Netty 以用于 Spring WebFlux:

The following Gradle example configures the necessary dependencies and a {url-gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement] to use Undertow in place of Reactor Netty for Spring WebFlux:

dependencies {
	implementation "org.springframework.boot:spring-boot-starter-undertow"
	implementation "org.springframework.boot:spring-boot-starter-webflux"
	modules {
		module("org.springframework.boot:spring-boot-starter-reactor-netty") {
			replacedBy("org.springframework.boot:spring-boot-starter-undertow", "Use Undertow instead of Reactor Netty")
		}
	}
}

spring-boot-starter-reactor-netty 是使用 WebClient 类所需的,因此即使你需要包含其他 HTTP 服务器也需要保留对 Netty 的依赖项。

spring-boot-starter-reactor-netty is required to use the WebClient class, so you may need to keep a dependency on Netty even when you need to include a different HTTP server.

Disabling the Web Server

如果类路径包含启动 Web 服务器的必需部分,Spring Boot 会自动启动它。要禁用此行为,可在 application.properties 中配置 WebApplicationType,如下例所示:

If your classpath contains the necessary bits to start a web server, Spring Boot will automatically start it. To disable this behavior configure the WebApplicationType in your application.properties, as shown in the following example:

spring:
  main:
    web-application-type: "none"

Change the HTTP Port

在独立应用程序中,主要 HTTP 端口默认为 8080,但可以用 configprop:server.port[] 设置(例如在 application.properties 中或作为系统属性)。由于 Environment 值的约束已被弱化,你还可以使用 configprop:server.port[format=envvar](例如作为操作系统环境变量)。

In a standalone application, the main HTTP port defaults to 8080 but can be set with configprop:server.port[] (for example, in application.properties or as a System property). Thanks to relaxed binding of Environment values, you can also use configprop:server.port[format=envvar] (for example, as an OS environment variable).

要完全关闭 HTTP 端点但仍然创建 WebApplicationContext,请使用 server.port=-1(这样做有时对于测试很有用)。

To switch off the HTTP endpoints completely but still create a WebApplicationContext, use server.port=-1 (doing so is sometimes useful for testing).

有关更多详细信息,请参阅“Spring Boot 功能部分中的 “Customizing Embedded Servlet Containers” 或 {code-spring-boot-autoconfigure-src}/web/ServerProperties.java[ServerProperties] 源代码。

For more details, see “Customizing Embedded Servlet Containers” in the '`Spring Boot Features’ section, or the {code-spring-boot-autoconfigure-src}/web/ServerProperties.java[ServerProperties] source code.

Use a Random Unassigned HTTP Port

要扫描空闲端口(使用操作系统本地方法来防止冲突),请使用 server.port=0

To scan for a free port (using OS natives to prevent clashes) use server.port=0.

Discover the HTTP Port at Runtime

可以通过日志输出或通过其 WebServerWebServerApplicationContext 访问服务器正在运行的端口。最佳做法是添加类型为 ApplicationListener<WebServerInitializedEvent>@Bean,并在发布事件时将容器从中移除,以便获取端口并确保已初始化。

You can access the port the server is running on from log output or from the WebServerApplicationContext through its WebServer. The best way to get that and be sure it has been initialized is to add a @Bean of type ApplicationListener<WebServerInitializedEvent> and pull the container out of the event when it is published.

使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) 的测试还可以通过使用 @LocalServerPort 注释将实际端口注入字段,如下例所示:

Tests that use @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) can also inject the actual port into a field by using the @LocalServerPort annotation, as shown in the following example:

@LocalServerPort@Value("${local.server.port}") 的元注释。不要尝试在常规应用程序中注入端口。正如我们刚才所看到的,该值在容器初始化之后才设置。与测试相反,应用程序代码回调在早期进行处理(在值实际可用之前)。

@LocalServerPort is a meta-annotation for @Value("${local.server.port}"). Do not try to inject the port in a regular application. As we just saw, the value is set only after the container has been initialized. Contrary to a test, application code callbacks are processed early (before the value is actually available).

Enable HTTP Response Compression

HTTP 响应压缩受 Jetty、Tomcat、Reactor Netty 和 Undertow 支持。它可以在 application.properties 中启用,如下所示:

HTTP response compression is supported by Jetty, Tomcat, Reactor Netty, and Undertow. It can be enabled in application.properties, as follows:

server:
  compression:
    enabled: true

默认情况下,响应长度必须至少达到 2048 个字节才能执行压缩。你可以通过设置 configprop:server.compression.min-response-size[] 属性来配置此行为。

By default, responses must be at least 2048 bytes in length for compression to be performed. You can configure this behavior by setting the configprop:server.compression.min-response-size[] property.

默认情况下,只有相应内容类型为以下类型之一时,才会对其进行压缩:

By default, responses are compressed only if their content type is one of the following:

  • text/html

  • text/xml

  • text/plain

  • text/css

  • text/javascript

  • application/javascript

  • application/json

  • application/xml

你可以通过设置 configprop:server.compression.mime-types[] 属性来配置此行为。

You can configure this behavior by setting the configprop:server.compression.mime-types[] property.

Configure SSL

可以通过设置各种 server.ssl.* 属性来以声明的方式配置 SSL,通常在 application.propertiesapplication.yaml 中设置。以下示例演示了使用 Java KeyStore 文件设置 SSL 属性:

SSL can be configured declaratively by setting the various server.ssl.* properties, typically in application.properties or application.yaml. The following example shows setting SSL properties using a Java KeyStore file:

server:
  port: 8443
  ssl:
    key-store: "classpath:keystore.jks"
    key-store-password: "secret"
    key-password: "another-secret"

使用前述示例中的配置意味着该应用程序不再支持端口 8080 上的纯 HTTP 连接器。Spring Boot 不支持通过 application.properties 配置 HTTP 连接器和 HTTPS 连接器。如果你希望同时使用这两者,则需要通过编程方式配置其中之一。我们建议使用 application.properties 来配置 HTTPS,因为在两个连接器中,HTTP 连接器更容易通过编程方式进行配置。

Using configuration such as the preceding example means the application no longer supports a plain HTTP connector at port 8080. Spring Boot does not support the configuration of both an HTTP connector and an HTTPS connector through application.properties. If you want to have both, you need to configure one of them programmatically. We recommend using application.properties to configure HTTPS, as the HTTP connector is the easier of the two to configure programmatically.

Using PEM-encoded files

您可以使用 PEM 编码文件,而不是 Java 密钥库文件。应尽可能使用 PKCS#8 密钥文件。PEM 编码的 PKCS#8 密钥文件以 -----BEGIN PRIVATE KEY----------BEGIN ENCRYPTED PRIVATE KEY----- 头部开头。

You can use PEM-encoded files instead of Java KeyStore files. You should use PKCS#8 key files wherever possible. PEM-encoded PKCS#8 key files start with a -----BEGIN PRIVATE KEY----- or -----BEGIN ENCRYPTED PRIVATE KEY----- header.

如果您有其他格式的文件,例如 PKCS#1 (-----BEGIN RSA PRIVATE KEY-----) 或 SEC 1 (-----BEGIN EC PRIVATE KEY-----),可以使用 OpenSSL 将其转换成 PKCS#8:

If you have files in other formats, e.g., PKCS#1 (-----BEGIN RSA PRIVATE KEY-----) or SEC 1 (-----BEGIN EC PRIVATE KEY-----), you can convert them to PKCS#8 using OpenSSL:

openssl pkcs8 -topk8 -nocrypt -in <input file> -out <output file>

以下示例演示了使用 PEM 编码证书和私钥文件设置 SSL 属性:

The following example shows setting SSL properties using PEM-encoded certificate and private key files:

server:
  port: 8443
  ssl:
    certificate: "classpath:my-cert.crt"
    certificate-private-key: "classpath:my-cert.key"
    trust-certificate: "classpath:ca-cert.crt"

或者,SSL 信任材料可以在 SSL bundle 中进行配置,并如示例所示应用于 Web 服务器:

Alternatively, the SSL trust material can be configured in an SSL bundle and applied to the web server as shown in this example:

server:
  port: 8443
  ssl:
    bundle: "example"

server.ssl.bundle 属性不能与 server.ssl 下的离散 Java 密钥库或 PEM 属性选项结合使用。

The server.ssl.bundle property can not be combined with the discrete Java KeyStore or PEM property options under server.ssl.

有关所有受支持属性的详情,请参阅 {code-spring-boot-src}/web/server/Ssl.java[Ssl]。

See {code-spring-boot-src}/web/server/Ssl.java[Ssl] for details of all of the supported properties.

Configure HTTP/2

您可以使用 configprop:server.http2.enabled[] 配置属性在 Spring Boot 应用程序中启用 HTTP/2 支持。h2(通过 TLS 进行的 HTTP/2)和 h2c(通过 TCP 进行的 HTTP/2)均受支持。要使用 h2,还必须启用 SSL。当 SSL 未启用时,将使用 h2c。例如,当您的应用程序是 running behind a proxy server 并执行 TLS 终结时,您可能希望使用 h2c

You can enable HTTP/2 support in your Spring Boot application with the configprop:server.http2.enabled[] configuration property. Both h2 (HTTP/2 over TLS) and h2c (HTTP/2 over TCP) are supported. To use h2, SSL must also be enabled. When SSL is not enabled, h2c will be used. You may, for example, want to use h2c when your application is running behind a proxy server that is performing TLS termination.

HTTP/2 With Tomcat

Spring Boot 默认与 Tomcat 10.1.x 捆绑,该 Tomcat 开箱即用地支持 h2ch2。或者,如果您在主机操作系统上安装了该库及其依赖项,可以使用 libtcnative 来获得 h2 支持。

Spring Boot ships by default with Tomcat 10.1.x which supports h2c and h2 out of the box. Alternatively, you can use libtcnative for h2 support if the library and its dependencies are installed on the host operating system.

如果尚未将库目录提供给 JVM 库路径,则必须提供它。可以使用 -Djava.library.path=/usr/local/opt/tomcat-native/lib 这样的 JVM 参数来实现此目的。有关此内容,请参阅 {url-tomcat-docs}/apr.html[官方 Tomcat 文档]。

The library directory must be made available, if not already, to the JVM library path. You can do so with a JVM argument such as -Djava.library.path=/usr/local/opt/tomcat-native/lib. More on this in the {url-tomcat-docs}/apr.html[official Tomcat documentation].

HTTP/2 With Jetty

对于 HTTP/2 支持,Jetty 需要附加的 org.eclipse.jetty.http2:jetty-http2-server 依赖项。要使用 h2c,不需要其他依赖项。要使用 h2,您还需根据所用的部署选择以下依赖项之一:

For HTTP/2 support, Jetty requires the additional org.eclipse.jetty.http2:jetty-http2-server dependency. To use h2c no other dependencies are required. To use h2, you also need to choose one of the following dependencies, depending on your deployment:

  • org.eclipse.jetty:jetty-alpn-java-server to use the JDK built-in support

  • org.eclipse.jetty:jetty-alpn-conscrypt-server and the Conscrypt library

HTTP/2 With Reactor Netty

spring-boot-webflux-starter 默认使用 Reactor Netty 作为服务器。Reactor Netty 开箱即用地支持 h2ch2。为了获得最佳运行时性能,此服务器还支持具有本机库的 h2。为了启用该库,您的应用程序需要具有附加的依赖项。

The spring-boot-webflux-starter is using by default Reactor Netty as a server. Reactor Netty supports h2c and h2 out of the box. For optimal runtime performance, this server also supports h2 with native libraries. To enable that, your application needs to have an additional dependency.

Spring Boot 管理用于 io.netty:netty-tcnative-boringssl-static 的“超级 jar”的版本,该“超级 jar”包含针对所有平台的本机库。开发人员可以选择仅使用分类器导入必需的依赖项(请参阅 the Netty official documentation)。

Spring Boot manages the version for the io.netty:netty-tcnative-boringssl-static "uber jar", containing native libraries for all platforms. Developers can choose to import only the required dependencies using a classifier (see the Netty official documentation).

HTTP/2 With Undertow

Undertow 开箱即用地支持 h2ch2

Undertow supports h2c and h2 out of the box.

Configure the Web Server

通常,您首先应考虑使用众多可用的配置密钥之一,并通过在 application.propertiesapplication.yaml 文件中添加新条目来自定义 Web 服务器。请参阅 “Discover Built-in Options for External Properties”)。server. namespace is quite useful here, and it includes namespaces like server.tomcat.server.jetty.* 和其他,用于与服务器相关的功能。请参阅 Common Application Properties 列表。

Generally, you should first consider using one of the many available configuration keys and customize your web server by adding new entries in your application.properties or application.yaml file. See “Discover Built-in Options for External Properties”). The server. namespace is quite useful here, and it includes namespaces like server.tomcat., server.jetty.* and others, for server-specific features. See the list of Common Application Properties.

前面的章节已涵盖了许多常见的使用案例,例如压缩、SSL 或 HTTP/2。但是,如果不存在适用于您使用案例的配置密钥,那么您应该查看 WebServerFactoryCustomizer。您可以声明这样的组件,并获得针对您选择的合适的服务器工厂:您应该为所选的服务器(Tomcat、Jetty、Reactor Netty、Undertow)和所选的 Web 堆栈(servlet 或 reactive)选择变体。

The previous sections covered already many common use cases, such as compression, SSL or HTTP/2. However, if a configuration key does not exist for your use case, you should then look at WebServerFactoryCustomizer. You can declare such a component and get access to the server factory relevant to your choice: you should select the variant for the chosen Server (Tomcat, Jetty, Reactor Netty, Undertow) and the chosen web stack (servlet or reactive).

以下示例适用于 Tomcat 和 spring-boot-starter-web(servlet 堆栈):

The example below is for Tomcat with the spring-boot-starter-web (servlet stack):

Spring Boot 在内部使用该基础设施来自动配置服务器。自动配置的 WebServerFactoryCustomizer Bean 具有 0 优先级,并且在处理任何用户定义的定制器之前会被处理,除非它明确声明了其他的优先级。

Spring Boot uses that infrastructure internally to auto-configure the server. Auto-configured WebServerFactoryCustomizer beans have an order of 0 and will be processed before any user-defined customizers, unless it has an explicit order that states otherwise.

一旦您使用定制器访问了 WebServerFactory,您就可以使用它为特定部分、如连接器、服务器资源或服务器本身配置,所有这些都使用特定于服务器的 API。

Once you have got access to a WebServerFactory using the customizer, you can use it to configure specific parts, like connectors, server resources, or the server itself - all using server-specific APIs.

此外,Spring Boot 提供:

In addition Spring Boot provides:

Server Servlet stack Reactive stack

Tomcat

TomcatServletWebServerFactory

TomcatReactiveWebServerFactory

Jetty

JettyServletWebServerFactory

JettyReactiveWebServerFactory

Undertow

UndertowServletWebServerFactory

UndertowReactiveWebServerFactory

Reactor

N/A

NettyReactiveWebServerFactory

作为最后手段,您也可以声明自己的 WebServerFactory Bean,它将覆盖 Spring Boot 提供的 Bean。当您这样做时,自动配置的定制器仍会被应用到您的自定义工厂中,因此要小心使用该选项。

As a last resort, you can also declare your own WebServerFactory bean, which will override the one provided by Spring Boot. When you do so, auto-configured customizers are still applied on your custom factory, so use that option carefully.

Add a Servlet, Filter, or Listener to an Application

在 servlet 堆栈应用程序中,即带有 spring-boot-starter-web 的,有两种方法可以向您的应用程序添加 ServletFilterServletContextListener 以及 Servlet API 支持的其他侦听器:

In a servlet stack application, that is with the spring-boot-starter-web, there are two ways to add Servlet, Filter, ServletContextListener, and the other listeners supported by the Servlet API to your application:

Add a Servlet, Filter, or Listener by Using a Spring Bean

要使用 Spring Bean 添加 ServletFilter 或 Servlet *Listener,您必须提供其 @Bean 定义。当您想注入配置或依赖关系时,这样做非常有用。但是,您必须非常小心,以避免过早地初始化许多其他 Bean,因为它们必须在应用程序生命周期的早期安装到容器中。(例如,让他们依赖您的 DataSource 或 JPA 配置不是一个好主意。)您可以在首次使用时而不是在初始化时懒惰地初始化 Bean 来解决此类限制。

To add a Servlet, Filter, or servlet *Listener by using a Spring bean, you must provide a @Bean definition for it. Doing so can be very useful when you want to inject configuration or dependencies. However, you must be very careful that they do not cause eager initialization of too many other beans, because they have to be installed in the container very early in the application lifecycle. (For example, it is not a good idea to have them depend on your DataSource or JPA configuration.) You can work around such restrictions by initializing the beans lazily when first used instead of on initialization.

在过滤器和 servlet 的情况下,您还可以添加映射和初始化参数,方法是添加 FilterRegistrationBeanServletRegistrationBean,而不是或除了基础组件。

In the case of filters and servlets, you can also add mappings and init parameters by adding a FilterRegistrationBean or a ServletRegistrationBean instead of or in addition to the underlying component.

如果过滤器注册中未指定 dispatcherType,则使用 REQUEST。这与 servlet 规范的默认调度程序类型一致。

If no dispatcherType is specified on a filter registration, REQUEST is used. This aligns with the servlet specification’s default dispatcher type.

与任何其他 Spring Bean 一样,您也可以定义 servlet 过滤器 Bean 的顺序;请务必查看 “Registering Servlets, Filters, and Listeners as Spring Beans” 部分。

Like any other Spring bean, you can define the order of servlet filter beans; please make sure to check the “Registering Servlets, Filters, and Listeners as Spring Beans” section.

Disable Registration of a Servlet or Filter

described earlier 一样,任何 ServletFilter Bean 都将自动注册到 servlet 容器中。要禁用特定 FilterServlet Bean 的注册,请为其创建注册 Bean 并将其标记为禁用,如下例所示:

As described earlier, any Servlet or Filter beans are registered with the servlet container automatically. To disable registration of a particular Filter or Servlet bean, create a registration bean for it and mark it as disabled, as shown in the following example:

Add Servlets, Filters, and Listeners by Using Classpath Scanning

@WebServlet@WebFilter@WebListener 注释类可以通过使用 @ServletComponentScan 注释 @Configuration 类并指定要注册的组件所包含的包来自动注册到嵌入式 servlet 容器中。默认情况下,@ServletComponentScan 从注释类的包进行扫描。

@WebServlet, @WebFilter, and @WebListener annotated classes can be automatically registered with an embedded servlet container by annotating a @Configuration class with @ServletComponentScan and specifying the package(s) containing the components that you want to register. By default, @ServletComponentScan scans from the package of the annotated class.

Configure Access Logging

可以通过其各自的名称空间为 Tomcat、Undertow 和 Jetty 配置访问日志。

Access logs can be configured for Tomcat, Undertow, and Jetty through their respective namespaces.

例如,以下设置使用 {url-tomcat-docs}/config/valve.html#Access_Logging[自定义模式] 在 Tomcat 上记录访问。

For instance, the following settings log access on Tomcat with a {url-tomcat-docs}/config/valve.html#Access_Logging[custom pattern].

server:
  tomcat:
    basedir: "my-tomcat"
    accesslog:
      enabled: true
      pattern: "%t %a %r %s (%D microseconds)"

日志的默认位置是 Tomcat 基本目录相对路径的 logs 目录。默认情况下,logs 目录是一个临时目录,因此您可能希望修复 Tomcat 的基本目录或使用日志的绝对路径。在前面的示例中,日志在应用程序工作目录相对路径的 my-tomcat/logs 中提供。

The default location for logs is a logs directory relative to the Tomcat base directory. By default, the logs directory is a temporary directory, so you may want to fix Tomcat’s base directory or use an absolute path for the logs. In the preceding example, the logs are available in my-tomcat/logs relative to the working directory of the application.

Undertow 的访问日志记录可以按照类似的方式进行配置,如下例所示:

Access logging for Undertow can be configured in a similar fashion, as shown in the following example:

server:
  undertow:
    accesslog:
      enabled: true
      pattern: "%t %a %r %s (%D milliseconds)"
    options:
      server:
        record-request-start-time: true

请注意,除了启用访问日志记录和配置其模式外,还启用了记录请求开始时间。在访问日志模式中包含响应时间 (%D) 时需要这样做。日志存储在应用程序工作目录相对路径的 logs 目录中。您可以通过设置 configprop:server.undertow.accesslog.dir[] 属性来自定义此位置。

Note that, in addition to enabling access logging and configuring its pattern, recording request start times has also been enabled. This is required when including the response time (%D) in the access log pattern. Logs are stored in a logs directory relative to the working directory of the application. You can customize this location by setting the configprop:server.undertow.accesslog.dir[] property.

最后,还可以如下配置 Jetty 的访问日志记录:

Finally, access logging for Jetty can also be configured as follows:

server:
  jetty:
    accesslog:
      enabled: true
      filename: "/var/log/jetty-access.log"

默认情况下,会将日志重定向至 System.err。有关更多详细信息,请参阅 Jetty 文档。

By default, logs are redirected to System.err. For more details, see the Jetty documentation.

Running Behind a Front-end Proxy Server

如果你的应用程序在代理、负载均衡器或云端后面运行,请求信息(如主机、端口、方案……)可能会发生更改。你的应用程序可能在 10.10.10.10:8080 上运行,但 HTTP 客户端只能看到 example.org

If your application is running behind a proxy, a load-balancer or in the cloud, the request information (like the host, port, scheme…​) might change along the way. Your application may be running on 10.10.10.10:8080, but HTTP clients should only see example.org.

RFC7239 "Forwarded Headers" 定义了 Forwarded HTTP 标头;代理可使用此标头提供有关原始请求的信息。你可以配置应用程序来读取这些标头,并在 HTTP 302 响应、JSON 文档或 HTML 页面中创建链接并将其发送给客户端时自动使用该信息。还有一些非标准标头,如 X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-SslX-Forwarded-Prefix

RFC7239 "Forwarded Headers" defines the Forwarded HTTP header; proxies can use this header to provide information about the original request. You can configure your application to read those headers and automatically use that information when creating links and sending them to clients in HTTP 302 responses, JSON documents or HTML pages. There are also non-standard headers, like X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl, and X-Forwarded-Prefix.

如果代理添加常用的 X-Forwarded-ForX-Forwarded-Proto 标头,将 server.forward-headers-strategy 设置为 NATIVE 足以支持这些标头。通过此选项,Web 服务器本身会本机化支持此功能;你可以查阅其特定文档,了解具体行为。

If the proxy adds the commonly used X-Forwarded-For and X-Forwarded-Proto headers, setting server.forward-headers-strategy to NATIVE is enough to support those. With this option, the Web servers themselves natively support this feature; you can check their specific documentation to learn about specific behavior.

如果这还不够,Spring Framework 会为 servlet 堆栈提供一个 {url-spring-framework-docs}/web/webmvc/filters.html#filters-forwarded-headers[ForwardedHeaderFilter],为响应式堆栈提供一个 {url-spring-framework-docs}/web/webflux/reactive-spring.html#webflux-forwarded-headers[ForwardedHeaderTransformer]。你可以将它们用于你的应用程序,方法是将 configprop:server.forward-headers-strategy[] 设置为 FRAMEWORK

If this is not enough, Spring Framework provides a {url-spring-framework-docs}/web/webmvc/filters.html#filters-forwarded-headers[ForwardedHeaderFilter] for the servlet stack and a {url-spring-framework-docs}/web/webflux/reactive-spring.html#webflux-forwarded-headers[ForwardedHeaderTransformer] for the reactive stack. You can use them in your application by setting configprop:server.forward-headers-strategy[] to FRAMEWORK.

如果你正在使用 Tomcat 并终止代理处的 SSL,则应该将 configprop:server.tomcat.redirect-context-root[] 设置为 false。这使得在执行任何重定向之前,可以处理 X-Forwarded-Proto 标头。

If you are using Tomcat and terminating SSL at the proxy, configprop:server.tomcat.redirect-context-root[] should be set to false. This allows the X-Forwarded-Proto header to be honored before any redirects are performed.

如果你的应用程序在 Cloud Foundry、Heroku 或 Kubernetes 中运行,configprop:server.forward-headers-strategy[] 属性默认为 NATIVE。在所有其他情况下,其默认为 NONE

If your application runs in Cloud Foundry, Heroku or Kubernetes, the configprop:server.forward-headers-strategy[] property defaults to NATIVE. In all other instances, it defaults to NONE.

Customize Tomcat’s Proxy Configuration

如果你使用 Tomcat,你可以另外配置用于承载 “forwarded” 信息的标头的名称,如下面的示例所示:

If you use Tomcat, you can additionally configure the names of the headers used to carry “forwarded” information, as shown in the following example:

server:
  tomcat:
    remoteip:
      remote-ip-header: "x-your-remote-ip-header"
      protocol-header: "x-your-protocol-header"

Tomcat 还会配置一个用于匹配要信任的内部代理的正则表达式。有关其默认值,请参阅附录中的 configprop:server.tomcat.remoteip.internal-proxies[ 条目。你可以通过向 application.properties 中添加条目来自定义阀值的配置,如下面的示例所示:

Tomcat is also configured with a regular expression that matches internal proxies that are to be trusted. See the configprop:server.tomcat.remoteip.internal-proxies[ entry in the appendix] for its default value. You can customize the valve’s configuration by adding an entry to application.properties, as shown in the following example:

server:
  tomcat:
    remoteip:
      internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}"

你可以将 internal-proxies 设置为空,从而信任所有代理(但在生产中不要这样做)。

You can trust all proxies by setting the internal-proxies to empty (but do not do so in production).

你可以通过关闭自动功能来完全控制 Tomcat 的 RemoteIpValve 配置(为此,请设置 server.forward-headers-strategy=NONE),并使用 WebServerFactoryCustomizer bean 添加新阀值实例。

You can take complete control of the configuration of Tomcat’s RemoteIpValve by switching the automatic one off (to do so, set server.forward-headers-strategy=NONE) and adding a new valve instance using a WebServerFactoryCustomizer bean.

Enable Multiple Connectors with Tomcat

你可以向 TomcatServletWebServerFactory 中添加一个 org.apache.catalina.connector.Connector,该 org.apache.catalina.connector.Connector 可以允许多个连接器,包括 HTTP 和 HTTPS 连接器,如下面的示例所示:

You can add an org.apache.catalina.connector.Connector to the TomcatServletWebServerFactory, which can allow multiple connectors, including HTTP and HTTPS connectors, as shown in the following example:

Enable Tomcat’s MBean Registry

默认情况下,禁用 Embedded Tomcat 的 MBean 注册表。这会最大程度减少 Tomcat 的内存占用。如果你希望使用 Tomcat 的 MBean(例如以使 Micrometer 可以使用它们来公开指标),你必须使用 configprop:server.tomcat.mbeanregistry.enabled[] 属性来执行此操作,如下面的示例所示:

Embedded Tomcat’s MBean registry is disabled by default. This minimizes Tomcat’s memory footprint. If you want to use Tomcat’s MBeans, for example so that they can be used by Micrometer to expose metrics, you must use the configprop:server.tomcat.mbeanregistry.enabled[] property to do so, as shown in the following example:

server:
  tomcat:
    mbeanregistry:
      enabled: true

Enable Multiple Listeners with Undertow

UndertowServletWebServerFactory 中添加一个 UndertowBuilderCustomizer,并向 Builder 中添加一个侦听器,如下面的示例所示:

Add an UndertowBuilderCustomizer to the UndertowServletWebServerFactory and add a listener to the Builder, as shown in the following example:

Create WebSocket Endpoints Using @ServerEndpoint

如果你希望在使用嵌入式容器的 Spring Boot 应用程序中使用 @ServerEndpoint,你必须声明单个 ServerEndpointExporter @Bean,如下面的示例所示:

If you want to use @ServerEndpoint in a Spring Boot application that used an embedded container, you must declare a single ServerEndpointExporter @Bean, as shown in the following example:

在前面的示例中显示的 bean 会使用底层 WebSocket 容器注册任何带 @ServerEndpoint 注释的 bean。当部署到独立的 servlet 容器时,servlet 容器初始化程序会执行此角色,不需要 ServerEndpointExporter bean。

The bean shown in the preceding example registers any @ServerEndpoint annotated beans with the underlying WebSocket container. When deployed to a standalone servlet container, this role is performed by a servlet container initializer, and the ServerEndpointExporter bean is not required.