|
如需使用最新稳定版本,请使用 Spring Integration 7.0.4! |
HTTP 命名空间支持
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-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"/>
请求映射支持
Spring Integration 3.0 通过引入 IntegrationRequestMappingHandlerMapping 改进了 REST 支持。
该实现依赖于 Spring Framework 3.1 或更高版本提供的增强型 REST 支持。 |
HTTP 入站网关或 HTTP 入站通道适配器的解析过程会注册一个类型为 IntegrationRequestMappingHandlerMapping 的 integrationRequestMappingHandlerMapping 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> 中。
它与 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。
The <request-mapping> 元素提供以下属性:
-
headers -
params -
consumes -
produces
使用 path 和 supported-methods 属性,或者 <http:inbound-channel-adapter> 或 <http:inbound-gateway> 的 <request-mapping> 属性,会直接映射为 Spring MVC 中 org.springframework.web.bind.annotation.RequestMapping 注解所提供的相应选项。
The <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 文档。
The IntegrationRequestMappingHandlerMapping extends the Spring MVC RequestMappingHandlerMapping class, inheriting most of its logic, especially handleNoMatch(Set, String, HttpServletRequest), which throws a specific 4xx error for the HTTP response, when mapping doesn't match for some reason, preventing calls to any remaining mapping handlers in the application context.
For this reason, configuring the same path for both Spring Integration and Spring MVC request mappings (e.g. POST in one and GET in the other) is not supported; the MVC mapping will not be found.. |
跨源资源共享 (CORS) 支持
从 4.2 版本开始,您可以使用 <http:inbound-channel-adapter> 元素来配置 <http:inbound-gateway> 和 <cross-origin>。
它与 Spring MVC 中用于 @CrossOrigin 注解的 @Controller 选项相同,并允许为 Spring Integration HTTP 端点配置跨域资源共享 (CORS):
-
origin: 允许的源列表。*表示允许所有源。 这些值将放置在预检请求和实际响应的Access-Control-Allow-Origin响应头中。 默认值为*。 -
allowed-headers: 指示在实际请求期间可以使用哪些请求头。*表示允许客户端请求的所有头信息。 此属性控制预检响应中的Access-Control-Allow-Headers头的值。 默认值为*。 -
exposed-headers: 用户代理允许客户端访问的响应头列表。 此属性控制实际响应的Access-Control-Expose-Headers头的值。 -
method: 允许的 HTTP 请求方法:GET,POST,HEAD,OPTIONS,PUT,PATCH,DELETE,TRACE。 此处指定的方法将覆盖supported-methods中的设置。 -
allow-credentials: 如果浏览器应包含与请求域关联的任何 Cookie,则设置为true;如果不应包含,则设置为false。 空字符串 ("") 表示未定义。 如果为true,预检响应将包含Access-Control-Allow-Credentials=true头。 默认值为true。 -
max-age: 控制预检响应(pre-flight responses)的缓存时长。 将此值设置为合理的数值可以减少浏览器所需的预检请求 - 响应交互次数。 此属性控制预检响应中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,该 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 状态Jetty,如下例所示:<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。
一个很好的候选者是异常的消息属性,这是在使用 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 负载(payload),而 {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 起,除了 payload 和 header 表达式中可用的现有 #pathVariables 和 #requestParams 变量外,我们还添加了其他有用的表达式变量:
-
#requestParams: 来自ServletRequestparameterMap的MultiValueMap。 -
#pathVariables: 来自 URI 模板占位符及其值的Map。 -
#matrixVariables: Spring MVC 规范中MultiValueMap的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。
请注意,所有这些值(以及其他值)都可以在下游消息流中的表达式中通过ThreadLocalorg.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-method为POST,默认响应类型为null。
当响应类型为null时,只要HTTP状态码成功(非成功状态码将抛出异常),回复的负载Message中将包含ResponseEntity。
如果您期望其他类型,例如String,请将其作为完全限定类名提供( preceding示例中的java.lang.String)。
另请参阅HTTP出站组件中关于空响应体的说明。
自 Spring Integration 2.1 版本起,HTTP 出站网关的 request-timeout 属性已重命名为 reply-timeout,以更准确地反映其意图。 |
|
自 Spring Integration 2.2 版本起,HTTP 上的 Java 序列化默认不再启用。
此前,当将 然而,由于这可能导致与现有应用程序不兼容,因此决定不再自动将此转换器添加到 HTTP 端点。
如果您希望使用 Java 序列化,可以通过使用 |
从 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 表达式,其中 在之前的版本中,一些用户使用占位符来用 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&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;
}
}
The uri-variables-expression must evaluate to a Map.
The values of the Map must be instances of String or Expression.
This Map is provided to an ExpressionEvalMap for further resolution of URI variable placeholders by using those expressions in the context of the outbound Message. |
重要提示
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()"
The 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() 来实现这一目的。
如前所述,一个手动构建的 MultiValueMap<String, String> 可以通过以下 Java Streams 代码片段转换为 List<NameValuePair> format() 方法参数:
List<NameValuePair> nameValuePairs =
params.entrySet()
.stream()
.flatMap(e -> e
.getValue()
.stream()
.map(v -> new BasicNameValuePair(e.getKey(), v)))
.collect(Collectors.toList());
控制 URI 编码
默认情况下,URL 字符串在发送请求前会被编码为 URI 对象(参见 UriComponentsBuilder)。
在某些涉及非标准 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 的情况下,使用带有其 UriBuilderFactory 的 WebClient。