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>
Inbound
XML 命名空间提供了用于处理 HTTP 入站请求的两个组件:inbound-channel-adapter
和 inbound-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"/>
Request Mapping Support
Spring Integration 3.0 通过引入 link:https://docs.spring.io/spring-integration/api/org/springframework/integration/http/inbound/IntegrationRequestMappingHandlerMapping.html[ |
HTTP 入站网关或 HTTP 入站通道适配器的解析会注册一个类型为 IntegrationRequestMappingHandlerMapping
的 integrationRequestMappingHandlerMapping`bean,如果尚未注册该 bean。 `HandlerMapping
的此特定实现将其逻辑委派给 RequestMappingInfoHandlerMapping
。该实现提供的功能类似于 Spring MVC 中的 org.springframework.web.bind.annotation.RequestMapping
注解。
有关详细信息,请参阅 link:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestmapping[Mapping Requests With |
为此,Spring Integration 3.0 引入了 <request-mapping>
元素。您可以在 <http:inbound-channel-adapter>
和 <http:inbound-gateway>
中添加此可选元素。它与 path
和 supported-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>
的 path
和 supported-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"/>
有关处理程序映射的更多信息,请参见 the Spring Framework Web Servlet documentation 或 the Spring Framework Web Reactive documentation。
IntegrationRequestMappingHandlerMapping
扩展了 Spring MVC RequestMappingHandlerMapping
类,继承了大部分逻辑,尤其是 handleNoMatch(Set, String, HttpServletRequest)
,当映射由于某一原因不匹配时,它会为 HTTP 响应抛出具体的 4xx
错误,从而阻止调用应用程序上下文中任何剩余的映射处理程序。出于此原因,不支持为 Spring Integration 和 Spring MVC 请求映射(例如,一个 POST
,另一个 GET
)配置相同的路径;MVC 映射将找不到。
Cross-origin Resource Sharing (CORS) Support
从 4.2 版本开始,你可以使用 <cross-origin>
元素配置 <http:inbound-channel-adapter>
和 <http:inbound-gateway>
。它表示与 Spring MVC 的 @CrossOrigin
针对 @Controller
注解相同的选项,并允许为 Spring Integration HTTP 端点配置跨源资源共享 (CORS):
-
origin
: 允许的源列表。means that all origins are allowed. These values are placed in the
Access-Control-Allow-Origin
header of both the pre-flight and actual responses. The default value is。
-
allowed-headers
: 指示在实际请求期间可以使用哪些请求头。means that all headers requested by the client are allowed. This property controls the value of the pre-flight response’s
Access-Control-Allow-Headers
header. The default value is。
-
exposed-headers
: 用户代理允许客户端访问的响应头列表。此属性控制实际响应的Access-Control-Expose-Headers
标头的值。 -
method
: 允许的 HTTP 请求方法:GET
,POST
,HEAD
,OPTIONS
,PUT
,PATCH
,DELETE
,TRACE
。此处指定的方法将覆盖supported-methods
中的方法。 -
allow-credentials
: 将其设置为true
,如果浏览器应包含与请求的域关联的任何 cookie,或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 中。
Response Status Code
从 4.1 版本开始,你可以使用 status-code-expression
配置 <http:inbound-channel-adapter>
以覆盖默认的 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>
从回复 Message
的 http_statusCode
标题中解析“状态代码”。从 4.2 版本开始,当在 reply-timeout
中未收到回复时的默认响应状态代码是 500 Internal Server Error
。有两种方法可以修改此行为:
-
添加
reply-timeout-status-code-expression
。此项与入站适配器上的status-code-expression
的语义相同。 -
添加
error-channel
并返回带有 HTTP 状态代码标头的适当消息,如下例所示:[source, xml]
<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
,则对其进行评估。
以前,超时的默认状态代码为 |
同样从 5.4 版本开始,在准备请求消息时遇到的错误将被发送到错误通道(如果提供了)。有关抛出适当异常的决定应当通过检查异常来在错误流程中做出。以前,任何异常都会被简单抛出,导致 HTTP 500 服务器错误响应状态,但在某些情况下,问题可能是由不正确的请求参数造成的,所以应该改为抛出一个带有 4xx 客户端错误状态的 ResponseStatusException
。有关详细信息,请参阅 ResponseStatusException
。发送到此错误通道的 ErrorMessage
包含原始异常作为有效负载以进行分析。
URI Template Variables and Expressions
通过将 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 template patterns。
从 Spring Integration 3.0 开始,除了在有效负载和标题表达式中提供现有的 #pathVariables
和 #requestParams
变量外,我们还添加了其他有用的表达式变量:
-
#requestParams
:MultiValueMap
从ServletRequest
parameterMap
。 -
#pathVariables
:Map
从 URI 模板占位符及其值。 -
#matrixVariables
:根据 Spring MVC Specification 中的Map
.#matrixVariables
需要 Spring MVC 3.2 或更高版本。 -
#requestAttributes
:与当前请求关联的org.springframework.web.context.request.RequestAttributes
。 -
#requestHeaders
:当前请求中的org.springframework.http.HttpHeaders
对象。 -
#cookies
:当前请求中的MultiValueMap<String, Cookie>
实例的jakarta.servlet.http.Cookie
。
请注意,如果消息流程是单线程且存在于请求线程内,所有这些值(以及其他值)都可以通过 ThreadLocal
org.springframework.web.context.request.RequestAttributes
变量在下游消息流程中的表达式中访问。以下示例配置了一个使用 expression
属性的转换器:
<int-:transformer
expression="T(org.springframework.web.context.request.RequestContextHolder).
requestAttributes.request.queryString"/>
Outbound
要配置出站网关,你可以使用命名空间支持。以下代码段显示了出站 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-method`为 `POST
,默认响应类型为 null。对于空响应类型,只要 HTTP 状态是成功的(非成功的状态代码会引发异常),响应 Message`的负载就包含 `ResponseEntity
。如果您预计一种不同类型,例如 String
,请将其提供为完全限定的类名(在前一个示例中为 java.lang.String
)。另请参阅 HTTP Outbound Components中有关空响应正文的注释。
从 Spring Integration 2.1 开始,HTTP 出站网关的 request-timeout
属性已重命名为 reply-timeout
,以更好地反映其意图。
从 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,通过在类路径上具有 the Jackson library 即可启用。
从 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 表达式,以 |
Mapping URI Variables
如果您的 URL 包含 URI 变量,则可以通过使用 uri-variable
元素映射这些变量。此元素可供 HTTP 出站网关和 HTTP 出站通道适配器使用。以下示例将 zipCode
URI 变量映射到一个表达式:
<int-http:outbound-gateway id="trafficGateway"
url="https://local.yahooapis.com/trafficData?appid=YdnDemo&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
元素定义两个属性:“name”和“expression”。“name”属性标识 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;
}
}
|
重要信息:uriVariablesExpression
属性提供了一个非常强大的机制,用于计算 URI 变量。我们预计人们大多使用简单的表达式,例如前面的示例。但是,您还可以配置一些内容,例如 "@uriVariablesBean.populate(#root)",将返回的 map 中的一个表达式设为 `variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));
,其中的表达式通过名为 thing2
的邮件头动态提供。由于该邮件头可能来自不受信任的来源,因此 HTTP 出站端点在计算这些表达式时使用 SimpleEvaluationContext
。SimpleEvaluationContext
仅使用 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&b=B'"/>
</int-http:outbound-gateway>
在这种情况下,您必须手动提供 URL 编码。例如,您可以为此目的使用 org.apache.http.client.utils.URLEncodedUtils#format()
。如前所述,可以通过使用以下 Java Streams 片段将手动构建的 MultiValueMap<String, String>
转换为 List<NameValuePair>
format()
方法参数:
List<NameValuePair> nameValuePairs =
params.entrySet()
.stream()
.flatMap(e -> e
.getValue()
.stream()
.map(v -> new BasicNameValuePair(e.getKey(), v)))
.collect(Collectors.toList());
Controlling URI Encoding
默认情况下,在发送请求之前,会将 URL 字符串编码(请参见 link:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html[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 module和 Web Services module中类似的出站组件中应用相同的配置。对于非常复杂的场景,建议在外部提供的 `RestTemplate`上配置一个 `UriTemplateHandler
;或者在 WebFlux 的情况下 - 在其 WebClient`上进行配置 `UriBuilderFactory
。