HTTP 支持
HTTP 支持
Spring 集成的 HTTP 支持允许运行 HTTP 请求和处理入站 HTTP 请求。
HTTP 支持包括以下网关实现:和 .
另请参阅 WebFlux 支持。HttpInboundEndpoint
HttpRequestExecutingMessageHandler
您需要将此依赖项包含在您的项目中:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-http</artifactId>
<version>6.0.9</version>
</dependency>
compile "org.springframework.integration:spring-integration-http:6.0.9"
必须在目标 Servlet 容器上提供依赖项。jakarta.servlet:jakarta.servlet-api
Http 入站组件
要通过 HTTP 接收消息,您需要使用 HTTP 入站通道适配器或 HTTP 入站网关。
要支持 HTTP 入站适配器,需要将它们部署在 servlet 容器(如 Apache Tomcat 或 Jetty)中。
最简单的方法是使用 Spring 的HttpRequestHandlerServlet
,方法是在文件中提供以下 servlet 定义:web.xml
<servlet>
<servlet-name>inboundGateway</servlet-name>
<servlet-class>o.s.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
请注意,Servlet 名称与 Bean 名称匹配。
有关使用 的更多信息,请参阅使用 Spring 的远程处理和 Web 服务,这是 Spring 框架参考文档的一部分。HttpRequestHandlerServlet
如果你在 Spring MVC 应用程序中运行,那么上述显式 servlet 定义就不是必需的。 在这种情况下,网关的 Bean 名称可以与 URL 路径匹配,就像对 Spring MVC 控制器 Bean 所做的那样。 有关更多信息,请参阅 Web MVC 框架,它是 Spring 框架参考文档的一部分。
有关示例应用程序和相应的配置,请参阅 Spring 集成示例存储库。 它包含 HTTP 示例应用程序,该应用程序演示了 Spring 集成的 HTTP 支持。 |
以下示例 Bean 定义了一个 HTTP 入站端点:
<bean id="httpInbound"
class="org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway">
<property name="requestChannel" ref="httpRequestChannel" />
<property name="replyChannel" ref="httpReplyChannel" />
</bean>
接受实例列表,否则依赖于 default 列表。
转换器允许自定义从 到 的映射。
默认转换器封装了简单的策略,这些策略(例如)为内容类型以 开头的请求创建消息。
有关完整详细信息,请参阅 Javadoc。
可以设置一个附加标志 () 以及自定义列表,以在自定义转换器之后添加默认转换器。
默认情况下,此标志设置为 ,这意味着自定义转换器将替换默认列表。HttpRequestHandlingMessagingGateway
HttpMessageConverter
HttpServletRequest
Message
String
POST
text
mergeWithDefaultConverters
HttpMessageConverter
false
消息转换过程使用 (optional) 属性和传入标头。
从版本 4.3 开始,如果请求没有内容类型标头,则假定为 ,如 .
以前,此类消息的正文被忽略。requestPayloadType
Content-Type
application/octet-stream
RFC 2616
Spring Integration 2.0 实现了多部分文件支持。
如果请求已包装为 a ,则当您使用默认转换器时,该请求将转换为一个有效负载,该有效负载是包含的值,这些值可以是字节数组、字符串或 Spring 的实例,具体取决于各个部分的内容类型。MultipartHttpServletRequest
Message
MultiValueMap
MultipartFile
如果 bean 名称为 (与 Spring 期望的名称相同),则 HTTP 入站端点会在上下文中找到 a 。
如果它确实找到了该 bean,则会在入站请求映射器上启用对 multipart 文件的支持。
否则,当它尝试将 multipart file 请求映射到 Spring Integration 时,它将失败。
有关 Spring 对 的支持的更多信息,请参见 Spring 参考手册。MultipartResolver multipartResolver DispatcherServlet Message MultipartResolver |
如果您希望将 a 代理到另一台服务器,最好将其保持为原始形式。
要处理这种情况,请不要将 Bean 添加到上下文中。
将终端节点配置为需要请求,自定义消息转换器以包含 ,并禁用默认的 multipart 转换器。
您可能需要一些其他转换器来回复。
以下示例显示了这种安排:
|
当您向客户端发送响应时,您可以通过多种方式自定义网关的行为。
默认情况下,网关通过发回状态代码来确认已收到请求。
可以通过提供 Spring MVC 解析的 'viewName' 来自定义此响应。
如果网关需要对 的回复,则可以设置标志(constructor 参数)以使网关在创建 HTTP 响应之前等待回复。
下面的示例将网关配置为用作具有视图名称的 Spring MVC 控制器:200
ViewResolver
Message
expectReply
Message
<bean id="httpInbound"
class="org.springframework.integration.http.inbound.HttpRequestHandlingController">
<constructor-arg value="true" /> <!-- indicates that a reply is expected -->
<property name="requestChannel" ref="httpRequestChannel" />
<property name="replyChannel" ref="httpReplyChannel" />
<property name="viewName" value="jsonView" />
<property name="supportedMethodNames" >
<list>
<value>GET</value>
<value>DELETE</value>
</list>
</property>
</bean>
由于 的值 ,它会等待回复。
前面的示例还显示了如何自定义网关接受的 HTTP 方法,这些方法默认为 and。constructor-arg
true
POST
GET
回复消息在模型映射中可用。 默认情况下,该映射条目的键是 'reply',但您可以通过在终端节点的配置上设置 'replyKey' 属性来覆盖此默认值。
有效载荷验证
从版本 5.2 开始,可以为 HTTP 入站端点提供一个,以便在发送到通道之前检查有效负载。
此有效负载已经是转换和提取的结果,以缩小有关有价值数据的验证范围。
验证失败的处理与我们在 Spring MVC 错误处理中的处理完全相同。Validator
payloadExpression
HTTP 出站组件
本节描述了 Spring 集成的 HTTP 出站组件。
用HttpRequestExecutingMessageHandler
要配置 ,请编写类似于以下内容的 bean 定义:HttpRequestExecutingMessageHandler
<bean id="httpOutbound"
class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler">
<constructor-arg value="http://localhost:8080/example" />
<property name="outputChannel" ref="responseChannel" />
</bean>
此 Bean 定义通过委托给 .
反过来,该模板委托给实例列表,以从有效负载生成 HTTP 请求正文。
您可以配置这些转换器以及要使用的实例,如下例所示:RestTemplate
HttpMessageConverter
Message
ClientHttpRequestFactory
<bean id="httpOutbound"
class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler">
<constructor-arg value="http://localhost:8080/example" />
<property name="outputChannel" ref="responseChannel" />
<property name="messageConverters" ref="messageConverterList" />
<property name="requestFactory" ref="customRequestFactory" />
</bean>
默认情况下,HTTP 请求是使用 的实例生成的,该实例使用 JDK 。
还可以通过 来支持 Apache Commons HTTP Client 的使用,您可以注入 (如前所示)。SimpleClientHttpRequestFactory
HttpURLConnection
CommonsClientHttpRequestFactory
对于出站网关,网关生成的回复消息包含请求消息中存在的所有消息标头。 |
使用 Cookie
基本 cookie 支持由出站网关上的属性提供。
当设置为 (default is ) 时,在响应中从服务器接收的报头将转换为回复消息中的报头。
然后,此标头将用于后续发送。
这可实现简单的有状态交互,例如:transfer-cookies
true
false
Set-Cookie
Cookie
…→logonGateway→…→doWorkGateway→…→logoffGateway→…
如果为 ,则收到的任何报头都保持与回复消息中的相同,并在后续发送时被丢弃。transfer-cookies
false
Set-Cookie
Set-Cookie
空响应正文
HTTP 是一种请求-响应协议。
但是,响应可能没有正文,只有标头。
在这种情况下,它会生成一个有效载荷为 的回复,而不管提供的任何 .
根据 HTTP RFC 状态代码定义,有许多状态要求响应不得包含消息正文(例如)。
在某些情况下,对同一 URL 的调用可能会也可能不会返回响应正文。
例如,对 HTTP 资源的第一个请求返回 content,但第二个请求不返回 (返回 a )。
但是,在所有情况下,都会填充消息标头。
这可以在 HTTP 出站网关之后的某些路由逻辑中使用。
您还可以使用 '<payload-type-router/>' 将带有 a 的消息路由到与用于具有正文的响应不同的流。 |
预期响应类型
进一步说明空响应正文,如果响应确实包含正文,则必须提供适当的属性,否则,您会收到一个没有正文的 。
必须与响应中的(已配置或默认)实例和标头兼容。
这可以是抽象类,甚至可以是接口(例如,当您使用 Java serialization 和 时)。 |
从版本 5.5 开始,它公开了一个标志(默认情况下)以仅返回响应正文,或将整体作为回复消息有效负载返回,独立于提供的 .
如果 中不存在正文,则忽略此标志并返回整体。HttpRequestExecutingMessageHandler
extractResponseBody
true
ResponseEntity
expectedResponseType
ResponseEntity
ResponseEntity
HTTP 命名空间支持
Spring 集成提供了一个名称空间和相应的模式定义。
要将其包含在您的配置中,请在您的应用程序上下文配置文件中提供以下命名空间声明: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 集成 3.0 通过引入IntegrationRequestMappingHandlerMapping 改进了 REST 支持。
该实现依赖于 Spring Framework 3.1 或更高版本提供的增强 REST 支持。 |
HTTP 入站网关或 HTTP 入站通道适配器的解析将注册 IntegrationRequestMappingHandlerMapping
类型的 Bean(如果尚未注册)。
HandlerMapping
的这个特定实现将其逻辑委托给 RequestMappingInfoHandlerMapping
。
该实现提供的功能类似于 Spring MVC 中的 org.springframework.web.bind.annotation.RequestMapping
注释。integrationRequestMappingHandlerMapping
有关更多信息,请参阅使用 @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>
根据前面的配置,名称空间解析器创建一个实例(如果不存在)和一个 bean,并将一个RequestMapping
的实例与之关联。
反过来,这个实例被转换为 Spring MVC RequestMappingInfo
。IntegrationRequestMappingHandlerMapping
HttpRequestHandlingController
RequestMapping
该元素提供以下属性:<request-mapping>
-
headers
-
params
-
consumes
-
produces
使用或,属性的 and 属性直接转换为 Spring MVC 中的 Comments 提供的相应选项。path
supported-methods
<http:inbound-channel-adapter>
<http:inbound-gateway>
<request-mapping>
org.springframework.web.bind.annotation.RequestMapping
该元素允许您将多个 Spring 集成 HTTP 入站端点配置为相同(甚至相同),并允许您根据传入的 HTTP 请求提供不同的下游消息流。<request-mapping>
path
supported-methods
或者,你也可以只声明一个 HTTP 入站端点,并在 Spring 集成流中应用路由和过滤逻辑来实现相同的结果。
这使您可以尽早进入流程。
以下示例显示了如何执行此操作: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 文档。
它扩展了 Spring MVC 类,继承了它的大部分逻辑,特别是 ,当 map 由于某种原因不匹配时,它会为 HTTP 响应抛出一个特定的错误,从而阻止调用应用程序上下文中任何剩余的 mapping 处理程序。
出于这个原因,为 Spring Integration 和 Spring MVC 请求映射配置相同的路径(例如 在一个和另一个中)不受支持;找不到 MVC 映射..IntegrationRequestMappingHandlerMapping RequestMappingHandlerMapping handleNoMatch(Set, String, HttpServletRequest) 4xx POST GET |
跨域资源共享 (CORS) 支持
从版本 4.2 开始,您可以使用 element 配置 and。
它表示与 Spring MVC 的 Comments 选项相同,并允许为 Spring 集成 HTTP 端点配置跨域资源共享(CORS):<http:inbound-channel-adapter>
<http:inbound-gateway>
<cross-origin>
@CrossOrigin
@Controller
-
origin
:允许的源列表。 表示允许所有源。 这些值都放在 pre-flight 和 actual 响应的标头中。 默认值为 .*
Access-Control-Allow-Origin
*
-
allowed-headers
:指示在实际请求期间可以使用哪些请求标头。 这意味着允许客户端请求的所有标头。 此属性控制飞行前响应的 header 的值。 默认值为 .*
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,或者是否不应包含。 空字符串 (“”) 表示未定义。 如果 ,则飞行前响应包括 Header。 默认值为 .true
false
true
Access-Control-Allow-Credentials=true
true
-
max-age
:控制飞行前响应的缓存持续时间。 将此值设置为合理的值可以减少浏览器所需的飞行前请求-响应交互的数量。 此属性控制 pre-flight 响应中 header 的值。 值 表示 undefined。 默认值为 1800 秒(30 分钟)。Access-Control-Max-Age
-1
CORS Java 配置由类表示,该类的实例可以注入到 bean 中。org.springframework.integration.http.inbound.CrossOrigin
HttpRequestHandlingEndpointSupport
响应状态代码
从版本 4.1 开始,您可以使用 a 配置 以覆盖默认状态。
表达式必须返回一个可以转换为枚举值的对象。
从版本 5.1 开始,具有 and,作为 root 对象提供。
例如,在运行时解决一些返回状态代码值的作用域 bean。
但是,它很可能设置为固定值,如 (No Content) 或 .
默认情况下,为 null,表示返回正常的“200 OK”响应状态。
使用 as root 对象,状态代码可以是有条件的,例如在请求方法、某些标头、URI 内容甚至请求正文上。
以下示例显示如何将状态代码设置为 :<http:inbound-channel-adapter>
status-code-expression
200 OK
org.springframework.http.HttpStatus
evaluationContext
BeanResolver
RequestEntity<?>
status-code=expression="204"
status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"
status-code-expression
RequestEntity<?>
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>
从回复的标题中解析“状态代码”。
从版本 4.2 开始,当 中没有收到回复时,默认响应状态代码是 .
有两种方法可以修改此行为:<http:inbound-gateway>
http_statusCode
Message
reply-timeout
500 Internal Server Error
-
添加 . 这与入站适配器上的语义相同。
reply-timeout-status-code-expression
status-code-expression
-
添加并返回带有 HTTP 状态代码标头的相应消息,如下例所示:
error-channel
<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>
的有效负载是一个 .
它必须转换为网关可以转换的内容,例如 .
一个很好的候选对象是异常的 message 属性,这是使用该技术时使用的值。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 客户端错误状态的 a。
有关更多信息,请参阅。
发送到此错误通道包含原始异常作为分析的有效负载。
==== URI 模板变量和表达式ResponseStatusException
ResponseStatusException
ErrorMessage
通过将 attribute 与 attribute 和 element 结合使用,您可以高度灵活地映射入站请求数据。path
payload-expression
header
在以下示例配置中,入站通道适配器配置为使用以下 URI 接受请求:
/first-name/{firstName}/last-name/{lastName}
使用该属性时, URI 模板变量 Map 为有效负载,而 URI template 变量映射到消息标头,如以下示例中所定义:payload-expression
{firstName}
Message
{lastName}
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 Reference Manual 中的 uri 模板模式。
从 Spring Integration 3.0 开始,除了在有效负载和 Headers 表达式中可用的现有和变量之外,我们还添加了其他有用的表达式变量:#pathVariables
#requestParams
-
#requestParams
:来自 .MultiValueMap
ServletRequest
parameterMap
-
#pathVariables
:from URI 模板占位符及其值。Map
-
#matrixVariables
:根据 Spring MVC 规范。 请注意,这需要 Spring MVC 3.2 或更高版本。Map
MultiValueMap
#matrixVariables
-
#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"/>
出境
要配置出站网关,您可以使用命名空间支持。 以下代码片段显示了出站 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' 属性。
这是两个最常见的配置值。
默认值为 ,默认响应类型为 null。
对于 null 响应类型,回复的有效负载包含 ,只要其 HTTP 状态为 成功(不成功的状态代码会引发异常)。
如果您需要其他类型,例如 a ,请将其作为完全限定的类名(在前面的示例中为 )。
另请参阅有关 HTTP 出站组件中空响应正文的说明。http-method
POST
Message
ResponseEntity
String
java.lang.String
从 Spring Integration 2.1 开始,HTTP 出站网关的属性被重命名为以更好地反映其意图。request-timeout reply-timeout |
从 Spring Integration 2.2 开始,默认情况下不再启用基于 HTTP 的 Java 序列化。
以前,在将属性设置为对象时,未正确设置标头。
从 Spring Integration 2.2 开始,现在已经更新为将标头设置为 . 但是,由于这可能会导致与现有应用程序不兼容,因此决定不再自动将此转换器添加到 HTTP 端点。
如果您希望使用 Java 序列化,则可以通过使用属性(当您使用 XML 配置时)或使用方法(在 Java 配置中)将 添加到相应的端点。
或者,您可能希望考虑改用 JSON,这是通过在 Classpath 上使用 Jackson 库来启用的。 |
从 Spring 集成 2.2 开始,你还可以使用 SPEL 和属性动态确定 HTTP 方法。
请注意,此属性与 是互斥的。
您还可以使用该属性而不是提供任何确定响应类型的有效 SPEL 表达式。
以下配置示例使用:http-method-expression
http-method
expected-response-type-expression
expected-response-type
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 表达式,以 the 作为根对象,它启用动态 url。
表达式计算结果的 URL 仍然可以包含 URI 变量的占位符。 在以前的版本中,一些用户使用占位符将整个 URL 替换为 URI 变量。 Spring 3.1 中的更改可能会导致一些转义字符问题,例如 '?'。 因此,如果您希望完全在运行时生成 URL,我们建议您使用 'url-expression' 属性。 |
映射 URI 变量
如果您的 URL 包含 URI 变量,则可以使用该元素映射它们。
此元素可用于 HTTP 出站网关和 HTTP 出站通道适配器。
以下示例将 URI 变量映射到表达式:uri-variable
zipCode
<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 变量的名称,而该属性用于设置实际值。
通过使用该属性,您可以利用 Spring 表达式语言 (SpEL) 的全部功能,这使您可以完全动态地访问消息有效负载和消息标头。
例如,在前面的配置中,在 的 payload 对象上调用该方法,并且该方法的结果用作名为 'zipCode' 的 URI 变量的值。uri-variable
name
expression
name
expression
expression
getZip()
Message
从 Spring Integration 3.0 开始,HTTP 出站端点支持该属性来指定应该评估的 an,从而在 URL 模板中产生所有 URI 变量占位符。
它提供了一种机制,通过该机制,您可以根据出站消息使用不同的变量表达式。
此属性与 element 互斥。
以下示例演示如何使用该属性:uri-variables-expression
expression
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 变量占位符。uri-variables-expression Map Map String Expression Map ExpressionEvalMap Message |
重要
该属性提供了一种非常强大的机制来评估 URI 变量。
我们预计人们主要使用简单的表达式,例如前面的示例。
但是,您也可以配置一些内容,例如在返回的映射中使用表达式 ,其中表达式在名为 的消息标头中动态提供。
由于标头可能来自不受信任的源,因此 HTTP 出站终端节点在评估这些表达式时使用。
它仅使用 SPEL 功能的子集。
如果您信任您的消息源并希望使用受限制的 SPEL 构造,请将出站终端节点的属性设置为 。uriVariablesExpression
"@uriVariablesBean.populate(#root)"
variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));
thing2
SimpleEvaluationContext
SimpleEvaluationContext
trustedSpel
true
通过使用自定义和一些实用程序来构建和编码 URL 参数,您可以实现需要基于每条消息提供一组动态 URI 变量的方案。
以下示例显示了如何执行此操作:url-expression
url-expression="T(org.springframework.web.util.UriComponentsBuilder)
.fromHttpUrl('https://HOST:PORT/PATH')
.queryParams(payload)
.build()
.toUri()"
该方法需要 a 作为参数,因此您可以在执行请求之前提前构建一组真实的 URL 查询参数。queryParams()
MultiValueMap<String, String>
整体也可以表示为 ,如下例所示: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 编码。
例如,您可以使用 for this purpose.
如前所述,可以使用以下 Java Streams 代码段将手动构建的参数转换为 method 参数:org.apache.http.client.utils.URLEncodedUtils#format()
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());
控制 URI 编码
默认情况下,在发送请求之前,URL 字符串被编码(请参阅 UriComponentsBuilder
)到 URI 对象。
在某些具有非标准 URI(例如 RabbitMQ REST API)的情况下,不需要执行编码。
的 and 提供了一个属性。
要禁用 URL 编码,请将此属性设置为 (默认情况下为 )。
如果您希望对 URL 的某些部分进行部分编码,请在 中使用 an,如下例所示:<http:outbound-gateway/>
<http:outbound-channel-adapter/>
encoding-mode
NONE
TEMPLATE_AND_VALUES
expression
<uri-variable/>
<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,此选项可由选项控制。
相同的配置适用于 WebFlux 模块和 Web 服务模块中的类似出站组件。
对于更复杂的场景,建议在外部提供的 ;或者在 WebFlux 的情况下 - 使用它。BaseHttpMessageHandlerSpec.encodingMode()
UriTemplateHandler
RestTemplate
WebClient
UriBuilderFactory
使用 Java 配置 HTTP 端点
以下示例显示如何使用 Java 配置入站网关:
@Bean
public HttpRequestHandlingMessagingGateway inbound() {
HttpRequestHandlingMessagingGateway gateway =
new HttpRequestHandlingMessagingGateway(true);
gateway.setRequestMapping(mapping());
gateway.setRequestPayloadType(String.class);
gateway.setRequestChannelName("httpRequest");
return gateway;
}
@Bean
public RequestMapping mapping() {
RequestMapping requestMapping = new RequestMapping();
requestMapping.setPathPatterns("/foo");
requestMapping.setMethods(HttpMethod.POST);
return requestMapping;
}
以下示例显示如何使用 Java DSL 配置入站网关:
@Bean
public IntegrationFlow inbound() {
return IntegrationFlow.from(Http.inboundGateway("/foo")
.requestMapping(m -> m.methods(HttpMethod.POST))
.requestPayloadType(String.class))
.channel("httpRequest")
.get();
}
以下示例显示如何使用 Java 配置出站网关:
@ServiceActivator(inputChannel = "httpOutRequest")
@Bean
public HttpRequestExecutingMessageHandler outbound() {
HttpRequestExecutingMessageHandler handler =
new HttpRequestExecutingMessageHandler("http://localhost:8080/foo");
handler.setHttpMethod(HttpMethod.POST);
handler.setExpectedResponseType(String.class);
return handler;
}
以下示例显示如何使用 Java DSL 配置出站网关:
@Bean
public IntegrationFlow outbound() {
return IntegrationFlow.from("httpOutRequest")
.handle(Http.outboundGateway("http://localhost:8080/foo")
.httpMethod(HttpMethod.POST)
.expectedResponseType(String.class))
.get();
}
超时处理
在 HTTP 组件的上下文中,必须考虑两个计时区域:
-
与 Spring 集成通道交互时的超时
-
与远程 HTTP 服务器交互时超时
这些组件与消息通道交互,可以为其指定超时。 例如,HTTP 入站网关将从连接的 HTTP 客户端收到的消息转发到消息通道(使用请求超时),因此 HTTP 入站网关从用于生成 HTTP 响应的回复通道(使用回复超时)接收回复消息。 下图提供了直观的说明:
对于出站终端节点,我们需要考虑在与远程服务器交互时 timing 的工作原理。 下图显示了此方案:
在使用 HTTP 出站网关或 HTTP 出站通道适配器发出活动 HTTP 请求时,您可能希望配置与 HTTP 相关的超时行为。
在这些情况下,这两个组件使用 Spring 的 RestTemplate
支持来执行 HTTP 请求。
要为 HTTP 出站网关和 HTTP 出站通道适配器配置超时,可以直接引用 Bean(通过使用该属性),也可以提供对ClientHttpRequestFactory
Bean 的引用(通过使用该属性)。
Spring 提供了接口的以下实现:RestTemplate
rest-template
request-factory
ClientHttpRequestFactory
-
SimpleClientHttpRequestFactory
:使用标准 J2SE 工具发出 HTTP 请求 -
HttpComponentsClientHttpRequestFactory
:使用 Apache HttpComponents HttpClient(自 Spring 3.1 起)
如果未显式配置 or 属性,则会实例化默认值(使用 )。request-factory
rest-template
RestTemplate
SimpleClientHttpRequestFactory
对于某些 JVM 实现,类对超时的处理可能不一致。 例如,来自 Java™ Platform, Standard Edition 6 API 规范中的: 此方法的某些非标准实现可能会忽略指定的超时。
要查看该集合,请调用 getConnectTimeout()。
如果您有特定需求,则应测试您的超时。
考虑使用 ,而 则使用 Apache HttpComponents HttpClient,而不是依赖 JVM 提供的实现。 |
当您将 Apache HttpComponents HttpClient 与池连接管理器一起使用时,您应该知道,默认情况下,连接管理器为每个给定路由创建的并发连接不超过 2 个,总共不超过 20 个连接。 对于许多实际应用程序,这些限制可能被证明过于限制。 请参阅 Apache 文档 以了解有关配置此重要组件的信息。 |
以下示例使用分别配置了 5 秒的 connect 和 read 超时的 来配置 HTTP 出站网关:SimpleClientHttpRequestFactory
<int-http:outbound-gateway url="https://samples.openweathermap.org/data/2.5/weather?q={city}"
http-method="GET"
expected-response-type="java.lang.String"
request-factory="requestFactory"
request-channel="requestChannel"
reply-channel="replyChannel">
<int-http:uri-variable name="city" expression="payload"/>
</int-http:outbound-gateway>
<bean id="requestFactory"
class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="connectTimeout" value="5000"/>
<property name="readTimeout" value="5000"/>
</bean>
HTTP 出站网关
对于 HTTP 出站网关,XML 架构仅定义 reply-timeout。
reply-timeout 映射到org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler类的sendTimeout属性。
更准确地说,该属性是在扩展类上设置的,而扩展类最终会在 .AbstractReplyProducingMessageHandler
MessagingTemplate
sendTimeout 属性的值默认为 “-1”,并将应用于连接的 .
这意味着,根据实现,Message Channel 的 send 方法可能会无限期地阻塞。
此外,仅当实际的MessageChannel实现具有阻塞发送(例如“full”bounded QueueChannel)时,才使用sendTimeout属性。MessageChannel
HTTP 入站网关
对于 HTTP 入站网关,XML 架构定义属性,该属性用于设置类(在扩展类上)的属性。
还可以使用该特性映射到同一类上的属性。request-timeout
requestTimeout
HttpRequestHandlingMessagingGateway
MessagingGatewaySupport
reply-timeout
replyTimeout
两个 timeout 属性的默认值为 (1000 毫秒或 1 秒)。
最终,该属性用于在实例上设置 。
另一方面,该属性用于设置实例上的属性。1000ms
request-timeout
sendTimeout
MessagingTemplate
replyTimeout
receiveTimeout
MessagingTemplate
要模拟连接超时,您可以连接到不可路由的 IP 地址,例如 10.255.255.10。 |
HTTP 代理配置
如果您位于代理后面,并且需要为 HTTP 出站适配器或网关配置代理设置,则可以应用以下两种方法之一。 在大多数情况下,您可以依赖控制代理设置的标准 Java 系统属性。 否则,你可以为 HTTP 客户端请求工厂实例显式配置 Spring Bean。
标准 Java 代理配置
您可以设置三个系统属性来配置 HTTP 协议处理程序使用的代理设置:
-
http.proxyHost
:代理服务器的主机名。 -
http.proxyPort
:端口号(默认值为 )。80
-
http.nonProxyHosts
:应绕过代理直接访问的主机列表。 这是以 分隔的模式列表。 模式可能以通配符开头或结尾。 与这些模式之一匹配的任何主机都通过直接连接而不是代理来访问。|
*
对于 HTTPS,可以使用以下属性:
-
https.proxyHost
:代理服务器的主机名。 -
https.proxyPort
:端口号,默认值为 80。
Spring的SimpleClientHttpRequestFactory
如果你需要对代理配置进行更明确的控制,你可以使用 Spring 的并配置它的 'proxy' 属性,如下例所示:SimpleClientHttpRequestFactory
<bean id="requestFactory"
class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="proxy">
<bean id="proxy" class="java.net.Proxy">
<constructor-arg>
<util:constant static-field="java.net.Proxy.Type.HTTP"/>
</constructor-arg>
<constructor-arg>
<bean class="java.net.InetSocketAddress">
<constructor-arg value="123.0.0.1"/>
<constructor-arg value="8080"/>
</bean>
</constructor-arg>
</bean>
</property>
</bean>
HTTP 标头映射
Spring 集成为 HTTP 请求和 HTTP 响应提供了对 HTTP 头映射的支持。
默认情况下,所有标准 HTTP 标头都从消息映射到 HTTP 请求或响应标头,而无需进一步配置。
但是,如果您确实需要进一步的自定义,则可以利用命名空间支持来提供其他配置。
您可以提供以逗号分隔的标头名称列表,并且可以包含以 '*' 字符作为通配符的简单模式。
提供此类值将覆盖默认行为。
基本上,它假设您在那时完全处于控制之中。
但是,如果您确实希望包含所有标准 HTTP 标头,则可以使用快捷方式模式:和 .
下面的清单显示了两个示例(第一个使用通配符):HTTP_REQUEST_HEADERS
HTTP_RESPONSE_HEADERS
<int-http:outbound-gateway id="httpGateway"
url="http://localhost/test2"
mapped-request-headers="thing1, thing2"
mapped-response-headers="X-*, HTTP_RESPONSE_HEADERS"
channel="someChannel"/>
<int-http:outbound-channel-adapter id="httpAdapter"
url="http://localhost/test2"
mapped-request-headers="thing1, thing2, HTTP_REQUEST_HEADERS"
channel="someChannel"/>
适配器和网关使用 ,它现在为入站和出站适配器提供了两种静态工厂方法,以便可以应用正确的方向(根据需要将 HTTP 请求和响应映射到内部或外部)。DefaultHttpHeaderMapper
如果需要进一步定制,也可以独立配置一个,并通过 attribute 注入到适配器中。DefaultHttpHeaderMapper
header-mapper
在版本 5.0 之前,用户定义的非标准 HTTP 标头的默认前缀为 .
版本 5.0 将默认前缀更改为空字符串。
根据 RFC-6648,现在不鼓励使用此类前缀。
您仍然可以通过设置属性来自定义此选项。
以下示例为 HTTP 网关配置标头映射器:DefaultHttpHeaderMapper
X-
DefaultHttpHeaderMapper.setUserDefinedHeaderPrefix()
<int-http:outbound-gateway id="httpGateway"
url="http://localhost/test2"
header-mapper="headerMapper"
channel="someChannel"/>
<bean id="headerMapper" class="o.s.i.http.support.DefaultHttpHeaderMapper">
<property name="inboundHeaderNames" value="thing1*, *thing2, thing3"/>
<property name="outboundHeaderNames" value="a*b, d"/>
</bean>
如果您需要执行 支持以外的其他操作,则可以直接实现 strategy 接口并提供对实现的引用。DefaultHttpHeaderMapper
HeaderMapper
集成图控制器
从版本 4.3 开始,HTTP 模块提供了一个配置类注释和一个 XML 元素,以将其公开为 REST 服务。
有关更多信息,请参阅 Integration Graph。@EnableIntegrationGraphController
<int-http:graph-controller/>
IntegrationGraphServer
HTTP 示例
本节通过几个示例总结了我们对 Spring 集成的 HTTP 支持的介绍。
分段 HTTP 请求 — RestTemplate(客户端)和 Http 入站网关(服务器)
这个例子展示了使用 Spring 发送多部分 HTTP 请求并使用 Spring 集成 HTTP 入站适配器接收它是多么简单。
我们创建一个并使用多部分数据填充它。
The 通过将其转换为 .
此特定客户端发送一个由多个部分组成的 HTTP 请求,其中包含公司名称和图像文件(公司徽标)。
下面的清单显示了该示例:RestTemplate
MultiValueMap
RestTemplate
MultipartHttpServletRequest
RestTemplate template = new RestTemplate();
String uri = "http://localhost:8080/multipart-http/inboundAdapter.htm";
Resource s2logo =
new ClassPathResource("org/springframework/samples/multipart/spring09_logo.png");
MultiValueMap map = new LinkedMultiValueMap();
map.add("company", "SpringSource");
map.add("company-logo", s2logo);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("multipart", "form-data"));
HttpEntity request = new HttpEntity(map, headers);
ResponseEntity<?> httpResponse = template.exchange(uri, HttpMethod.POST, request, null);
这就是我们为客户提供的全部需求。
在服务器端,我们有以下配置:
<int-http:inbound-channel-adapter id="httpInboundAdapter"
channel="receiveChannel"
path="/inboundAdapter.htm"
supported-methods="GET, POST"/>
<int:channel id="receiveChannel"/>
<int:service-activator input-channel="receiveChannel">
<bean class="org.springframework.integration.samples.multipart.MultipartReceiver"/>
</int:service-activator>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
“httpInboundAdapter”接收请求并将其转换为负载为 .
然后,我们在 'multipartReceiver' 服务激活器中解析它,如下例所示:Message
LinkedMultiValueMap
public void receive(LinkedMultiValueMap<String, Object> multipartRequest){
System.out.println("### Successfully received multipart request ###");
for (String elementName : multipartRequest.keySet()) {
if (elementName.equals("company")){
System.out.println("\t" + elementName + " - " +
((String[]) multipartRequest.getFirst("company"))[0]);
}
else if (elementName.equals("company-logo")){
System.out.println("\t" + elementName + " - as UploadedMultipartFile: " +
((UploadedMultipartFile) multipartRequest
.getFirst("company-logo")).getOriginalFilename());
}
}
}
您应该会看到以下输出:
### Successfully received multipart request ###
company - SpringSource
company-logo - as UploadedMultipartFile: spring09_logo.png