HTTP 支持
HTTP 支持
Spring Integration 的 HTTP 支持允许运行 HTTP 请求和处理入站 HTTP 请求。
HTTP 支持由以下网关实现组成:HttpInboundEndpoint
和HttpRequestExecutingMessageHandler
.
另请参阅 WebFlux 支持。
您需要将此依赖项包含在您的项目中:
<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"
这jakarta.servlet:jakarta.servlet-api
必须在目标 Servlet 容器上提供依赖项。
Http 入站组件
要通过 HTTP 接收消息,您需要使用 HTTP 入站通道适配器或 HTTP 入站网关。
为了支持 HTTP 入站适配器,需要将它们部署在 Servlet 容器(例如 Apache Tomcat 或 Jetty)中。
最简单的方法是使用 Spring 的HttpRequestHandlerServlet
,通过在web.xml
文件:
<servlet>
<servlet-name>inboundGateway</servlet-name>
<servlet-class>o.s.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
请注意,servlet 名称与 bean 名称匹配。
有关使用HttpRequestHandlerServlet
,请参阅使用 Spring 的远程处理和 Web 服务,这是 Spring Framework 参考文档的一部分。
如果您在 Spring MVC 应用程序中运行,则不需要上述显式 servlet 定义。 在这种情况下,网关的 bean 名称可以与 URL 路径进行匹配,就像 Spring MVC Controller bean 一样。 有关更多信息,请参阅 Web MVC 框架,它是 Spring Framework 参考文档的一部分。
有关示例应用程序和相应的配置,请参阅 Spring Integration 示例存储库。 它包含 HTTP 示例应用程序,演示了 Spring Integration 的 HTTP 支持。 |
以下示例 bean 定义了一个 HTTP 入站端点:
<bean id="httpInbound"
class="org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway">
<property name="requestChannel" ref="httpRequestChannel" />
<property name="replyChannel" ref="httpReplyChannel" />
</bean>
这HttpRequestHandlingMessagingGateway
接受HttpMessageConverter
instances 或 else 依赖于默认列表。
转换器允许从HttpServletRequest
自Message
.
默认转换器封装了简单的策略,例如,这些策略创建了一个String
消息POST
请求,其中内容类型开头为text
.
有关完整详细信息,请参阅 Javadoc。
附加标志 (mergeWithDefaultConverters
) 可以与自定义列表一起设置HttpMessageConverter
在自定义转换器之后添加默认转换器。
默认情况下,此标志设置为false
,这意味着自定义转换器将替换默认列表。
消息转换过程使用(可选)requestPayloadType
属性和传入的Content-Type
页眉。
从 4.3 版开始,如果请求没有内容类型标头,application/octet-stream
被假定,如建议的那样RFC 2616
.
以前,此类消息的正文被忽略。
Spring Integration 2.0 实现了多部分文件支持。
如果请求已包装为MultipartHttpServletRequest
,当您使用默认转换器时,该请求将转换为Message
有效负载,即MultiValueMap
包含可能是字节数组、字符串或 Spring 的MultipartFile
,具体取决于各个部分的内容类型。
HTTP 入站端点找到一个MultipartResolver 在上下文中,如果一个 bean 名称为multipartResolver (与 Spring 的DispatcherServlet ).
如果它确实找到了该 bean,那么将在入站请求映射器上启用对多部分文件的支持。
否则,当它尝试将多部分文件请求映射到 Spring Integration 时,它会失败Message .
有关 Spring 对MultipartResolver ,请参阅 Spring 参考手册。 |
如果您希望代理
|
向客户端发送响应时,可以通过多种方式自定义网关的行为。
默认情况下,网关通过发送200
状态代码返回。
可以通过提供要由 Spring MVC 解析的“viewName”来自定义此响应ViewResolver
.
如果网关应该期望对Message
,您可以将expectReply
flag(构造函数参数)使网关等待回复Message
在创建 HTTP 响应之前。以下示例将网关配置为用作具有视图名称的 Spring MVC Controller:
<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>
因为constructor-arg
值true
,它等待回复。前面的示例还演示了如何自定义网关接受的 HTTP 方法,这些方法是POST
和GET
默认情况下。
回复消息在模型映射中可用。默认情况下,该映射条目的键是“reply”,但您可以通过在端点的配置上设置“replyKey”属性来覆盖此默认值。
有效负载验证
从版本 5.2 开始,可以为 HTTP 入站端点提供Validator
在发送到通道之前检查有效负载。此有效负载已经是转换和提取的结果payloadExpression
缩小有关有价值数据的验证范围。验证失败处理与我们在 Spring MVC 错误处理中完全相同。
HTTP 出站组件
本节介绍 Spring Integration 的 HTTP 出站组件。
用HttpRequestExecutingMessageHandler
要配置HttpRequestExecutingMessageHandler
,编写类似于以下内容的 bean 定义:
<bean id="httpOutbound"
class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler">
<constructor-arg value="http://localhost:8080/example" />
<property name="outputChannel" ref="responseChannel" />
</bean>
此 Bean 定义通过委托给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 请求是通过使用SimpleClientHttpRequestFactory
,它使用 JDKHttpURLConnection
. 通过以下方式还支持使用 Apache Commons HTTP 客户端CommonsClientHttpRequestFactory
,您可以注入(如前所示)。
对于出站网关,网关生成的回复消息包含请求消息中存在的所有消息头。 |
使用 Cookie
基本的 cookie 支持由transfer-cookies
属性。当设置为true
(默认值为false
)、一个Set-Cookie
响应中从服务器接收的标头将转换为Cookie
在回复消息中。然后,此标头将用于后续发送。这支持简单的有状态交互,例如:
…→logonGateway→…→doWorkGateway→…→logoffGateway→…
如果transfer-cookies
是false
任何Set-Cookie
收到的标头仍为Set-Cookie
并在后续发送时被删除。
空响应体
HTTP 是一种请求-响应协议。但是,响应可能没有正文,只有标头。在这种情况下, |
预期响应类型
继前面关于空响应正文的说明之后,如果响应确实包含正文,则必须提供适当的 |
从 5.5 版本开始,HttpRequestExecutingMessageHandler
暴露了一个extractResponseBody
标志(即true
默认情况下)仅返回响应正文,或返回整个ResponseEntity
作为回复消息有效负载,独立于提供的expectedResponseType
.
如果ResponseEntity
,这个标志被忽略了,整个ResponseEntity
被返回。
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 .
该实现依赖于 Spring Framework 3.1 或更高版本提供的增强的 REST 支持。 |
HTTP 入站网关或 HTTP 入站通道适配器的解析会注册一个integrationRequestMappingHandlerMapping
类型IntegrationRequestMappingHandlerMapping
,以防尚未注册。
这种特殊的实现HandlerMapping
将其逻辑委托给RequestMappingInfoHandlerMapping
.
该实现提供的功能类似于org.springframework.web.bind.annotation.RequestMapping
Spring MVC 中的注释。
有关更多信息,请参阅映射请求@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
instance 反过来转换为 Spring MVCRequestMappingInfo
.
这<request-mapping>
元素提供以下属性:
-
headers
-
params
-
consumes
-
produces
使用path
和supported-methods
属性<http:inbound-channel-adapter>
或<http:inbound-gateway>
,<request-mapping>
属性直接转换为org.springframework.web.bind.annotation.RequestMapping
Spring MVC 中的注释。
这<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 文档。
这IntegrationRequestMappingHandlerMapping 扩展 Spring MVCRequestMappingHandlerMapping 类,继承了它的大部分逻辑,尤其是handleNoMatch(Set, String, HttpServletRequest) ,这会抛出特定的4xx 错误,当映射由于某种原因不匹配时,阻止调用应用程序上下文中任何剩余的映射处理程序。
因此,为 Spring Integration 和 Spring MVC 请求映射配置相同的路径(例如POST 在一个和GET 在另一个)中,不支持;将找不到 MVC 映射。 |
跨域资源共享 (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
:设置为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
豆。
响应状态代码
从 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>
从http_statusCode
回复的标题Message
.
从 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 服务器错误响应状态,但在某些情况下,问题可能是由不正确的请求参数引起的,因此ResponseStatusException
应引发 4xx 客户端错误状态。
看ResponseStatusException
了解更多信息。
这ErrorMessage
发送到此错误通道的包含原始异常作为分析的有效负载。
==== URI 模板变量和表达式
通过使用path
属性与payload-expression
属性和header
元素,则具有高度的灵活性来映射入站请求数据。
在以下示例配置中,入站通道适配器配置为使用以下 URI 接受请求:
/first-name/{firstName}/last-name/{lastName}
当您使用payload-expression
属性,则{firstName}
URI 模板变量映射为Message
有效负载,而{lastName}
URI 模板变量映射到lname
message 标头,如以下示例中定义:
<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
:这MultiValueMap
从ServletRequest
parameterMap
. -
#pathVariables
:这Map
从 URI 模板占位符及其值。 -
#matrixVariables
:这Map
之MultiValueMap
根据 Spring MVC 规范。 请注意#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"/>
出境
若要配置出站网关,可以使用命名空间支持。 以下代码片段显示了出站 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 响应类型,则回复的有效负载Message
包含ResponseEntity
,只要其 HTTP 状态为成功(不成功的状态代码会抛出异常)。
如果您期望使用不同的类型,例如String
,将其作为完全限定的类名 (java.lang.String
在前面的示例中)。
另请参阅有关 HTTP 出站组件中空响应正文的说明。
从 Spring Integration 2.1 开始,request-timeout HTTP 出站网关的属性已重命名为reply-timeout 以更好地反映其意图。 |
从 Spring Integration 2.2 开始,默认情况下不再启用基于 HTTP 的 Java 序列化。
以前,在设置 但是,由于这可能会导致与现有应用程序不兼容,因此决定不再自动将此转换器添加到 HTTP 端点。
如果您希望使用 Java 序列化,可以将 |
从 Spring Integration 2.2 开始,您还可以使用 SpEL 和http-method-expression
属性。
请注意,此属性与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 表达式,其中 在以前的版本中,一些用户使用占位符将整个 URL 替换为 URI 变量。 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) 的全部功能,它使您可以完全动态地访问消息有效负载和消息头。
例如,在前面的配置中,getZip()
方法在Message
该方法的结果用作名为“zipCode”的 URI 变量的值。
从 Spring Integration 3.0 开始,HTTP 出站端点支持uri-variables-expression
属性来指定expression
应该评估,从而产生Map
URL 模板中所有 URI 变量占位符。
它提供了一种机制,您可以根据出站消息使用不同的变量表达式。
此属性与<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 必须是String 或Expression .
这Map 提供给ExpressionEvalMap 通过在出站上下文中使用这些表达式来进一步解析 URI 变量占位符Message . |
重要
这uriVariablesExpression
属性提供了一种非常强大的机制来评估 URI 变量。
我们预计人们大多使用简单的表达式,例如前面的示例。
但是,您也可以配置诸如"@uriVariablesBean.populate(#root)"
返回的映射中的表达式为variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));
,其中表达式在名为thing2
.
由于标头可能来自不受信任的来源,因此 HTTP 出站终结点使用SimpleEvaluationContext
在评估这些表达式时。
这SimpleEvaluationContext
仅使用 SpEL 要素的子集。
如果您信任您的消息源并希望使用受限的 SpEL 结构,请将trustedSpel
出站终结点的属性设置为true
.
可以使用自定义url-expression
以及一些用于构建和编码 URL 参数的实用程序。
以下示例显示了如何执行此作:
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()
为此目的。
如前所述,手动构建的MultiValueMap<String, String>
可以转换为List<NameValuePair>
format()
method 参数,使用以下 Java Streams 代码段:
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 的某些部分进行部分编码,请使用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,此选项可以通过BaseHttpMessageHandlerSpec.encodingMode()
选择。
相同的配置适用于 WebFlux 模块和 Web 服务模块中的类似出站组件。
对于非常复杂的方案,建议配置UriTemplateHandler
在外部提供的RestTemplate
;或者如果是 WebFlux -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 Integration Channels 交互时超时
-
与远程 HTTP 服务器交互时超时
组件与可以指定超时的消息通道交互。 例如,HTTP 入站网关将从连接的 HTTP 客户端接收的消息转发到消息通道(使用请求超时),因此 HTTP 入站网关从回复通道(使用回复超时)接收用于生成 HTTP 响应的回复消息。 下图提供了直观的解释:

对于出站端点,我们需要考虑与远程服务器交互时计时的工作原理。 下图显示了此方案:

在使用 HTTP 出站网关或 HTTP 出站通道适配器发出活动 HTTP 请求时,您可能希望配置与 HTTP 相关的超时行为。
在这些情况下,这两个组件使用 Spring 的RestTemplate
支持执行 HTTP 请求。
要为 HTTP 出站网关和 HTTP 出站通道适配器配置超时,您可以引用RestTemplate
bean 直接(通过使用rest-template
属性),或者您可以提供对ClientHttpRequestFactory
bean(通过使用request-factory
属性)。
Spring 提供了以下ClientHttpRequestFactory
接口:
-
SimpleClientHttpRequestFactory
:使用标准 J2SE 工具发出 HTTP 请求 -
HttpComponentsClientHttpRequestFactory
:使用 Apache HttpComponents HttpClient(从 Spring 3.1 开始)
如果您没有显式配置request-factory
或rest-template
属性,默认值RestTemplate
(它使用SimpleClientHttpRequestFactory
) 被实例化。
对于某些 JVM 实现,通过 例如,从 Java™ 平台标准版 6 API 规范 此方法的某些非标准实现可能会忽略指定的超时。
要查看
如果您有特定需求,则应测试超时时间。
考虑使用 |
将 Apache HttpComponents HttpClient 与池连接管理器一起使用时,您应该知道,默认情况下,连接管理器在每个给定路由创建的并发连接不超过两个,总共不超过 20 个连接。 对于许多实际应用来说,这些限制可能过于严格。 有关配置此重要组件的信息,请参阅 Apache 文档。 |
以下示例使用SimpleClientHttpRequestFactory
分别配置了 5 秒的连接和读取超时:
<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 映射到 org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler 类的 sendTimeout 属性。
更准确地说,该属性是在扩展的AbstractReplyProducingMessageHandler
类,最终将属性设置为MessagingTemplate
.
sendTimeout 属性的值默认为“-1”,并将应用于连接的MessageChannel
.
这意味着,根据实现,消息通道的发送方法可能会无限期地阻塞。
此外,仅当实际的 MessageChannel 实现具有阻塞发送(例如“完整”有界 QueueChannel)时,才使用 sendTimeout 属性。
HTTP 入站网关
对于 HTTP 入站网关,XML 模式定义了request-timeout
属性,用于设置requestTimeout
属性HttpRequestHandlingMessagingGateway
类(在扩展的MessagingGatewaySupport
类)。
您还可以使用reply-timeout
属性映射到replyTimeout
属性。
这两个超时属性的默认值为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 的SimpleClientHttpRequestFactory
并配置其“proxy”属性,如以下示例所示:
<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 Integration 为 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"/>
适配器和网关使用DefaultHttpHeaderMapper
,现在为入站和出站适配器提供了两种静态工厂方法,以便可以应用正确的方向(根据需要映射 HTTP 请求和响应)。
如果您需要进一步自定义,您还可以配置DefaultHttpHeaderMapper
独立并通过header-mapper
属性。
在 5.0 版本之前,DefaultHttpHeaderMapper
用户定义的非标准 HTTP 标头的默认前缀是X-
.
5.0 版将默认前缀更改为空字符串。
根据 RFC-6648,现在不鼓励使用此类前缀。
您仍然可以通过设置DefaultHttpHeaderMapper.setUserDefinedHeaderPrefix()
财产。
以下示例为 HTTP 网关配置标头映射器:
<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>
如果您需要执行的作不是DefaultHttpHeaderMapper
支持,您可以实现HeaderMapper
策略接口,并为您的实施提供参考。
集成图控制器
从 4.3 版开始,HTTP 模块提供了一个@EnableIntegrationGraphController
配置类注释和<int-http:graph-controller/>
XML 元素以公开IntegrationGraphServer
作为 REST 服务。
有关更多信息,请参阅集成图。
HTTP 示例
本节通过几个示例总结了我们对 Spring Integration 的 HTTP 支持的介绍。
多部分 HTTP 请求 — RestTemplate(客户端)和 Http 入站网关(服务器)
这个例子展示了使用 Spring 的RestTemplate
并使用 Spring Integration HTTP 入站适配器接收它。
我们创建一个MultiValueMap
并使用多部分数据填充它。
这RestTemplate
通过将其转换为MultipartHttpServletRequest
.
此特定客户端发送一个多部分 HTTP 请求,其中包含公司名称和图像文件(公司徽标)。
以下列表显示了示例:
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”接收请求并将其转换为Message
有效负载为LinkedMultiValueMap
.
然后,我们在 'multipartReceiver' 服务激活器中解析它,如以下示例所示:
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