跳到主要内容
版本:7.0.2

HTTP 命名空间支持

DeepSeek V3 中英对照 HTTP Namespace Support

Spring Integration 提供了一个 http 命名空间及相应的模式定义。要在配置中包含它,请在您的应用程序上下文配置文件中提供以下命名空间声明:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http
https://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
...
</beans>

入站

XML 命名空间提供了两个组件来处理 HTTP 入站请求:inbound-channel-adapterinbound-gateway。若要在不返回专用响应的情况下处理请求,请使用 inbound-channel-adapter。以下示例展示了如何配置一个:

<int-http:inbound-channel-adapter id="httpChannelAdapter" channel="requests"
supported-methods="PUT, DELETE"/>

对于需要响应的请求处理,请使用 inbound-gateway。以下示例展示了如何配置:

<int-http:inbound-gateway id="inboundGateway"
request-channel="requests"
reply-channel="responses"/>

请求映射支持

备注

Spring Integration 3.0 通过引入 IntegrationRequestMappingHandlerMapping 改进了 REST 支持。该实现依赖于 Spring Framework 3.1 或更高版本提供的增强 REST 支持。

HTTP入站网关或HTTP入站通道适配器的解析会注册一个类型为IntegrationRequestMappingHandlerMappingintegrationRequestMappingHandlerMapping bean,前提是该bean尚未注册。这个特殊的HandlerMapping实现将其逻辑委托给RequestMappingInfoHandlerMapping。该实现提供了类似于Spring MVC中org.springframework.web.bind.annotation.RequestMapping注解的功能。

备注

更多信息,请参阅 使用 @RequestMapping 映射请求

为此,Spring Integration 3.0 引入了 <request-mapping> 元素。您可以将此可选元素添加到 <http:inbound-channel-adapter><http:inbound-gateway> 中。它与 pathsupported-methods 属性配合使用。以下示例展示了如何在入站网关上配置它:

<inbound-gateway id="inboundController"
request-channel="requests"
reply-channel="responses"
path="/foo/{fooId}"
supported-methods="GET"
view-name="foo"
error-code="oops">
<request-mapping headers="User-Agent"
params="myParam=myValue"
consumes="application/json"
produces="!text/plain"/>
</inbound-gateway>

基于前述配置,命名空间解析器会创建一个 IntegrationRequestMappingHandlerMapping 实例(如果尚不存在)和一个 HttpRequestHandlingController bean,并将一个 RequestMapping 实例与之关联。这个 RequestMapping 实例随后会被转换为 Spring MVC 的 RequestMappingInfo

<request-mapping> 元素提供以下属性:

  • headers

  • params

  • consumes

  • produces

通过 <http:inbound-channel-adapter><http:inbound-gateway>pathsupported-methods 属性,<request-mapping> 属性直接转换为 Spring MVC 中 org.springframework.web.bind.annotation.RequestMapping 注解提供的相应选项。

<request-mapping> 元素允许您将多个 Spring Integration HTTP 入站端点配置到相同的 path(甚至相同的 supported-methods),并允许您根据传入的 HTTP 请求提供不同的下游消息流。

或者,你也可以只声明一个 HTTP 入站端点,并在 Spring Integration 流中应用路由和过滤逻辑来实现相同的结果。这让你可以尽早地将 Message 引入流中。以下示例展示了如何做到这一点:

<int-http:inbound-gateway request-channel="httpMethodRouter"
supported-methods="GET,DELETE"
path="/process/{entId}"
payload-expression="#pathVariables.entId"/>

<int:router input-channel="httpMethodRouter" expression="headers.http_requestMethod">
<int:mapping value="GET" channel="in1"/>
<int:mapping value="DELETE" channel="in2"/>
</int:router>

<int:service-activator input-channel="in1" ref="service" method="getEntity"/>

<int:service-activator input-channel="in2" ref="service" method="delete"/>

有关处理器映射的更多信息,请参阅 Spring Framework Web Servlet 文档Spring Framework Web Reactive 文档

important

IntegrationRequestMappingHandlerMapping 扩展了 Spring MVC 的 RequestMappingHandlerMapping 类,继承了其大部分逻辑,特别是 handleNoMatch(Set, String, HttpServletRequest) 方法。当映射因某些原因不匹配时,该方法会为 HTTP 响应抛出特定的 4xx 错误,从而阻止调用应用程序上下文中任何剩余的映射处理器。因此,不支持为 Spring Integration 和 Spring MVC 请求映射配置相同的路径(例如,一个使用 POST,另一个使用 GET);MVC 映射将不会被找到。

跨源资源共享(CORS)支持

从版本4.2开始,你可以使用 <cross-origin> 元素来配置 <http:inbound-channel-adapter><http:inbound-gateway>。该元素的功能与 Spring MVC 中 @Controller 注解的 @CrossOrigin 相同,允许为 Spring Integration HTTP 端点配置跨源资源共享(CORS):

  • origin: 允许的来源列表。* 表示允许所有来源。这些值会同时放入预检请求和实际响应的 Access-Control-Allow-Origin 头中。默认值为 *

  • allowed-headers: 指示在实际请求中可以使用哪些请求头。* 表示允许客户端请求的所有头。此属性控制预检响应中 Access-Control-Allow-Headers 头的值。默认值为 *

  • exposed-headers: 用户代理允许客户端访问的响应头列表。此属性控制实际响应中 Access-Control-Expose-Headers 头的值。

  • method: 允许的 HTTP 请求方法:GETPOSTHEADOPTIONSPUTPATCHDELETETRACE。此处指定的方法会覆盖 supported-methods 中的方法。

  • allow-credentials: 如果浏览器应包含与请求域关联的任何 cookie,则设置为 true;如果不应该包含,则设置为 false。空字符串 ("") 表示未定义。如果为 true,预检响应将包含 Access-Control-Allow-Credentials=true 头。默认值为 true

  • max-age: 控制预检响应的缓存时间。将此值设置为合理的数值可以减少浏览器所需的预检请求-响应交互次数。此属性控制预检响应中 Access-Control-Max-Age 头的值。值为 -1 表示未定义。默认值为 1800 秒(30 分钟)。

CORS Java配置由org.springframework.integration.http.inbound.CrossOrigin类表示,其实例可注入到HttpRequestHandlingEndpointSupport bean中。

响应状态码

从版本 4.1 开始,你可以通过配置 <http:inbound-channel-adapter>status-code-expression 来覆盖默认的 200 OK 状态。该表达式必须返回一个可转换为 org.springframework.http.HttpStatus 枚举值的对象。evaluationContext 包含一个 BeanResolver,并且从版本 5.1 开始,RequestEntity<?> 被作为根对象提供。例如,可以在运行时解析某个返回状态码值的作用域 bean。然而,更常见的情况是将其设置为固定值,例如 status-code-expression="204"(无内容),或 status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"。默认情况下,status-code-expression 为 null,这意味着返回正常的 '200 OK' 响应状态。通过将 RequestEntity<?> 作为根对象,可以根据请求方法、某些请求头、URI 内容甚至请求体来有条件地设置状态码。以下示例展示了如何将状态码设置为 ACCEPTED

<http:inbound-channel-adapter id="inboundController"
channel="requests" view-name="foo" error-code="oops"
status-code-expression="T(org.springframework.http.HttpStatus).ACCEPTED">
<request-mapping headers="BAR"/>
</http:inbound-channel-adapter>

<http:inbound-gateway> 会从回复 Messagehttp_statusCode 头部解析 '状态码'。从版本 4.2 开始,当在 reply-timeout 内未收到回复时,默认的响应状态码是 500 Internal Server Error。有两种方式可以修改此行为:

  • 添加 reply-timeout-status-code-expression。其语义与入站适配器上的 status-code-expression 相同。

  • 添加 error-channel 并返回带有适当 HTTP 状态码头的消息,如下例所示:

    <int:chain input-channel="errors">
    <int:header-enricher>
    <int:header name="http_statusCode" value="504" />
    </int:header-enricher>
    <int:transformer expression="payload.failedMessage" />
    </int:chain>

ErrorMessage 的有效载荷是一个 MessageTimeoutException。它必须转换为网关可以转换的内容,例如 String。一个很好的选择是异常的 message 属性,这是在使用 expression 技术时所使用的值。

如果错误流在主流程超时后也超时,将返回 500 Internal Server Error;或者,如果存在 reply-timeout-status-code-expression,则会对其进行求值。

备注

之前,超时的默认状态码是 200 OK。要恢复该行为,请设置 reply-timeout-status-code-expression="200"

此外,从版本5.4开始,在准备请求消息时遇到的错误会被发送到错误通道(如果已提供)。是否抛出适当的异常应在错误流中通过检查异常来决定。在此之前,任何异常都会被直接抛出,导致HTTP 500服务器错误响应状态,但在某些情况下,问题可能由不正确的请求参数引起,因此应抛出带有4xx客户端错误状态的 ResponseStatusException。更多信息请参阅 ResponseStatusException。发送到此错误通道的 ErrorMessage 包含原始异常作为有效负载以供分析。

URI 模板变量与表达式

通过结合使用 path 属性、payload-expression 属性以及 header 元素,您能够高度灵活地映射入站请求数据。

在以下示例配置中,入站通道适配器被配置为接受使用以下URI的请求:

/first-name/{firstName}/last-name/{lastName}

当你使用 payload-expression 属性时,{firstName} URI 模板变量会映射到 Message 负载,而 {lastName} URI 模板变量则会映射到 lname 消息头,如下例所示:

<int-http:inbound-channel-adapter id="inboundAdapterWithExpressions"
path="/first-name/{firstName}/last-name/{lastName}"
channel="requests"
payload-expression="#pathVariables.firstName">
<int-http:header name="lname" expression="#pathVariables.lastName"/>
</int-http:inbound-channel-adapter>

有关URI模板变量的更多信息,请参阅Spring参考手册中的URI模板模式

自 Spring Integration 3.0 起,除了现有的 #pathVariables#requestParams 变量可在负载和头部表达式中使用外,我们还添加了其他有用的表达式变量:

  • #requestParams: 来自 ServletRequest parameterMapMultiValueMap

  • #pathVariables: 来自 URI 模板占位符及其值的 Map

  • #matrixVariables: 根据 Spring MVC 规范MultiValueMapMap。请注意,#matrixVariables 需要 Spring MVC 3.2 或更高版本。

  • #requestAttributes: 与当前请求关联的 org.springframework.web.context.request.RequestAttributes

  • #requestHeaders: 来自当前请求的 org.springframework.http.HttpHeaders 对象。

  • #cookies: 来自当前请求的 jakarta.servlet.http.Cookie 实例的 MultiValueMap<String, Cookie>

请注意,所有上述值(及其他值)都可以在下游消息流中通过 ThreadLocal org.springframework.web.context.request.RequestAttributes 变量访问,前提是该消息流是单线程的且存在于请求线程内。以下示例配置了一个使用 expression 属性的转换器:

<int-:transformer
expression="T(org.springframework.web.context.request.RequestContextHolder).
requestAttributes.request.queryString"/>

出站

要配置出站网关,您可以使用命名空间支持。以下代码片段展示了出站 HTTP 网关的可用配置选项:

<int-http:outbound-gateway id="example"
request-channel="requests"
url="http://localhost/test"
http-method="POST"
extract-request-payload="false"
expected-response-type="java.lang.String"
charset="UTF-8"
request-factory="requestFactory"
reply-timeout="1234"
reply-channel="replies"/>

最重要的是,请注意其中提供了 'http-method' 和 'expected-response-type' 属性。这是两个最常配置的值。默认的 http-methodPOST,默认的响应类型为 null。当响应类型为 null 时,只要 HTTP 状态为成功(非成功状态码会抛出异常),回复 Message 的有效载荷就会包含 ResponseEntity。如果您期望不同的类型,例如 String,请将其作为完全限定类名提供(如前面示例中的 java.lang.String)。另请参阅 HTTP 出站组件 中关于空响应体的说明。

important

从 Spring Integration 2.1 开始,HTTP 出站网关的 request-timeout 属性已更名为 reply-timeout,以更好地反映其用途。

important

自 Spring Integration 2.2 起,默认不再启用基于 HTTP 的 Java 序列化。在此之前,当将 expected-response-type 属性设置为 Serializable 对象时,Accept 头部未能正确设置。自 Spring Integration 2.2 起,SerializingHttpMessageConverter 已更新为将 Accept 头部设置为 application/x-java-serialized-object

然而,由于这可能导致与现有应用程序不兼容,因此决定不再自动将此转换器添加到 HTTP 端点。如果您希望使用 Java 序列化,可以通过 message-converters 属性(在使用 XML 配置时)或使用 setMessageConverters() 方法(在 Java 配置中)将 SerializingHttpMessageConverter 添加到相应的端点。或者,您也可以考虑改用 JSON,这可以通过在类路径中包含 Jackson 库 来启用。

从 Spring Integration 2.2 开始,您还可以通过使用 SpEL 和 http-method-expression 属性来动态确定 HTTP 方法。请注意,此属性与 http-method 互斥。您还可以使用 expected-response-type-expression 属性代替 expected-response-type,并提供任何有效的 SpEL 表达式来确定响应的类型。以下配置示例使用了 expected-response-type-expression

<int-http:outbound-gateway id="example"
request-channel="requests"
url="http://localhost/test"
http-method-expression="headers.httpMethod"
extract-request-payload="false"
expected-response-type-expression="payload"
charset="UTF-8"
request-factory="requestFactory"
reply-timeout="1234"
reply-channel="replies"/>

如果你的出站适配器需要以单向方式使用,你可以使用 outbound-channel-adapter 来代替。这意味着成功的响应执行后不会向回复通道发送任何消息。对于任何非成功的响应状态码,它将抛出异常。配置方式与网关非常相似,如下例所示:

<int-http:outbound-channel-adapter id="example"
url="http://localhost/example"
http-method="GET"
channel="requests"
charset="UTF-8"
extract-payload="false"
expected-response-type="java.lang.String"
request-factory="someRequestFactory"
order="3"
auto-startup="false"/>
备注

要指定 URL,你可以使用 'url' 属性或 'url-expression' 属性。'url' 属性接受一个简单的字符串(包含 URI 变量的占位符,如下所述)。'url-expression' 是一个 SpEL 表达式,以 Message 作为根对象,它支持动态 URL。表达式求值得到的 URL 仍然可以包含 URI 变量的占位符。

在之前的版本中,一些用户使用占位符通过 URI 变量替换整个 URL。Spring 3.1 中的更改可能会导致一些转义字符(例如 '?')出现问题。因此,我们建议,如果你希望在运行时完全生成 URL,请使用 'url-expression' 属性。

映射URI变量

如果您的URL包含URI变量,您可以使用uri-variable元素来映射它们。该元素适用于HTTP出站网关和HTTP出站通道适配器。以下示例将zipCode URI变量映射到一个表达式:

<int-http:outbound-gateway id="trafficGateway"
url="https://local.yahooapis.com/trafficData?appid=YdnDemo&amp;zip={zipCode}"
request-channel="trafficChannel"
http-method="GET"
expected-response-type="java.lang.String">
<int-http:uri-variable name="zipCode" expression="payload.getZip()"/>
</int-http:outbound-gateway>

uri-variable 元素定义了两个属性:nameexpressionname 属性用于标识 URI 变量的名称,而 expression 属性则用于设置实际值。通过使用 expression 属性,您可以充分利用 Spring 表达式语言(SpEL)的强大功能,从而实现对消息负载和消息头的完全动态访问。例如,在上述配置中,会在 Message 的负载对象上调用 getZip() 方法,并将该方法的返回值用作名为 'zipCode' 的 URI 变量的值。

自 Spring Integration 3.0 起,HTTP 出站端点支持 uri-variables-expression 属性,用于指定一个应被求值的 expression,该表达式的结果是一个包含 URL 模板中所有 URI 变量占位符的 Map。它提供了一种机制,允许你根据出站消息使用不同的变量表达式。此属性与 <uri-variable/> 元素互斥。以下示例展示了如何使用 uri-variables-expression 属性:

<int-http:outbound-gateway
url="https://foo.host/{foo}/bars/{bar}"
request-channel="trafficChannel"
http-method="GET"
uri-variables-expression="@uriVariablesBean.populate(payload)"
expected-response-type="java.lang.String"/>

uriVariablesBean 可能定义如下:

public class UriVariablesBean {
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();

public Map<String, ?> populate(Object payload) {
Map<String, Object> variables = new HashMap<String, Object>();
if (payload instanceOf String.class)) {
variables.put("foo", "foo"));
}
else {
variables.put("foo", EXPRESSION_PARSER.parseExpression("headers.bar"));
}
return variables;
}

}
备注

uri-variables-expression 必须求值为一个 Map。该 Map 的值必须是 StringExpression 的实例。此 Map 会被提供给一个 ExpressionEvalMap,以便在出站 Message 的上下文中使用这些表达式来进一步解析 URI 变量占位符。

重要提示:uriVariablesExpression 属性为评估 URI 变量提供了非常强大的机制。我们预计用户主要会使用简单的表达式,例如前面的示例。然而,您也可以配置类似 "@uriVariablesBean.populate(#root)" 的表达式,其中返回的映射中的表达式为 variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));,其中表达式动态地由名为 thing2 的消息头提供。由于消息头可能来自不受信任的源,HTTP 出站端点在评估这些表达式时使用 SimpleEvaluationContextSimpleEvaluationContext 仅使用 SpEL 功能的一个子集。如果您信任消息源并希望使用受限的 SpEL 构造,请将出站端点的 trustedSpel 属性设置为 true

您可以通过使用自定义的 url-expression 以及一些用于构建和编码URL参数的实用工具,来实现需要在每条消息基础上提供动态URI变量集的场景。以下示例展示了如何实现:

url-expression="T(org.springframework.web.util.UriComponentsBuilder)
.fromHttpUrl('https://HOST:PORT/PATH')
.queryParams(payload)
.build()
.toUri()"

queryParams() 方法期望接收一个 MultiValueMap<String, String> 类型的参数,因此你可以在执行请求之前,预先构建一组实际的 URL 查询参数。

整个 queryString 也可以表示为 uri-variable,如下例所示:

<int-http:outbound-gateway id="proxyGateway" request-channel="testChannel"
url="http://testServer/test?{queryString}">
<int-http:uri-variable name="queryString" expression="'a=A&amp;b=B'"/>
</int-http:outbound-gateway>

在这种情况下,您必须手动提供URL编码。例如,您可以使用 org.apache.http.client.utils.URLEncodedUtils#format() 来实现此目的。如前所述,通过以下Java Streams代码片段,可以将手动构建的 MultiValueMap<String, String> 转换为 format() 方法的参数 List<NameValuePair>

List<NameValuePair> nameValuePairs =
params.entrySet()
.stream()
.flatMap(e -> e
.getValue()
.stream()
.map(v -> new BasicNameValuePair(e.getKey(), v)))
.collect(Collectors.toList());

控制 URI 编码

默认情况下,URL字符串在发送请求前会被编码(参见UriComponentsBuilder)为URI对象。在某些非标准URI的场景中(例如RabbitMQ REST API),可能不希望执行编码操作。<http:outbound-gateway/><http:outbound-channel-adapter/>提供了encoding-mode属性。要禁用URL编码,请将此属性设置为NONE(默认值为TEMPLATE_AND_VALUES)。若希望仅对URL的某部分进行编码,可在<uri-variable/>中使用expression,如下例所示:

<http:outbound-gateway url="https://somehost/%2f/fooApps?bar={param}" encoding-mode="NONE">
<http:uri-variable name="param"
expression="T(org.apache.commons.httpclient.util.URIUtil)
.encodeWithinQuery('Hello World!')"/>
</http:outbound-gateway>

通过 Java DSL,此选项可通过 BaseHttpMessageHandlerSpec.encodingMode() 选项进行控制。相同的配置适用于 WebFlux 模块Web Services 模块 中的类似出站组件。对于更复杂的场景,建议在外部提供的 RestTemplate 上配置 UriTemplateHandler;或者在 WebFlux 的情况下,为 WebClient 配置其 UriBuilderFactory