HTTP 支持
Spring Integration 的 HTTP 支持允许 HTTP 请求的运行和入站 HTTP 请求的处理。HTTP 支持包括以下网关实现:HttpInboundEndpoint
和HttpRequestExecutingMessageHandler
. 另请参阅WebFlux 支持。
您需要将此依赖项包含到您的项目中:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-http</artifactId>
<version>5.5.13</version>
</dependency>
compile "org.springframework.integration:spring-integration-http:5.5.13"
javax.servlet:javax.servlet-api
必须在目标 Servlet 容器上提供依赖项。
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 名称匹配。有关使用 的更多信息HttpRequestHandlerServlet
,请参阅使用 Spring 的远程处理和 Web 服务,它是 Spring 框架参考文档的一部分。
如果您在 Spring MVC 应用程序中运行,则不需要前面提到的显式 servlet 定义。在这种情况下,网关的 bean 名称可以与 URL 路径进行匹配,就像 Spring MVC 控制器 bean 一样。有关更多信息,请参阅 Web MVC 框架,它是 Spring 框架参考文档的一部分。
有关示例应用程序和相应的配置,请参阅Spring Integration Samples存储库。它包含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
依赖于默认列表。转换器允许自定义从HttpServletRequest
到的映射Message
。默认转换器封装了简单的策略,(例如)为内容类型以 . 开头String
的请求创建消息。有关完整的详细信息,请参阅Javadoc。可以与自定义列表一起设置附加标志 ( ),以在自定义转换器之后添加默认转换器。默认情况下,此标志设置为,这意味着自定义转换器替换默认列表。POST
text
mergeWithDefaultConverters
HttpMessageConverter
false
消息转换过程使用(可选)requestPayloadType
属性和传入Content-Type
标头。从 4.3 版开始,如果请求没有内容类型标头,application/octet-stream
则假定为RFC 2616
. 以前,此类消息的正文被忽略。
Spring Integration 2.0 实现了多部分文件支持。如果请求已包装为MultipartHttpServletRequest
,则当您使用默认转换器时,该请求将转换为包含值的Message
有效负载,该MultiValueMap
值可能是字节数组、字符串或 Spring 的实例MultipartFile
,具体取决于各个部分的内容类型.
MultipartResolver 如果一个 bean 名称为multipartResolver (与 Spring 的预期名称相同),则
HTTP 入站端点在上下文中定位 a DispatcherServlet 。如果它确实找到了该 bean,则在入站请求映射器上启用对多部分文件的支持。否则,它会在尝试将多部分文件请求映射到 Spring Integration 时失败Message 。有关 Spring 对 的支持的更多信息MultipartResolver ,请参阅Spring 参考手册。
|
如果您希望将 a 代理
|
当您向客户端发送响应时,您可以通过多种方式自定义网关的行为。默认情况下,网关通过发200
回状态码来确认已收到请求。可以通过提供由 Spring MVC 解析的“viewName”来自定义此响应ViewResolver
。如果网关应该期待对 的回复Message
,您可以设置标志(构造函数参数)以使网关在创建 HTTP 响应之前expectReply
等待回复。Message
以下示例将网关配置为具有视图名称的 Spring MVC 控制器:
<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 入站端点提供 aValidator
以在发送到通道之前检查有效负载。该有效载荷已经是转换和提取的结果,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
实例列表以从有效负载生成 HTTP 请求正文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
使用 JDK的实例生成的HttpURLConnection
。还支持使用 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
. 如果 body 中不存在,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
类型为 的 bean 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
反过来,这个实例被转换为 Spring MVC RequestMappingInfo
。
该<request-mapping>
元素提供以下属性:
-
headers
-
params
-
consumes
-
produces
使用或的path
和supported-methods
属性,属性直接转换为Spring MVC 中注解提供的相应选项。<http:inbound-channel-adapter>
<http:inbound-gateway>
<request-mapping>
org.springframework.web.bind.annotation.RequestMapping
该<request-mapping>
元素允许您将多个 Spring Integration HTTP 入站端点配置为相同path
(甚至相同supported-methods
),并允许您根据传入的 HTTP 请求提供不同的下游消息流。
或者,您也可以仅声明一个 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 文档。
IntegrationRequestMappingHandlerMapping 扩展了 Spring MVC类,继承了它
的RequestMappingHandlerMapping 大部分逻辑,尤其是,当映射由于某种原因不匹配时handleNoMatch(Set, String, HttpServletRequest) ,它会为 HTTP 响应引发特定错误,从而阻止调用应用程序上下文中的任何剩余映射处理程序。4xx 因此,不支持为 Spring Integration 和 Spring MVC 请求映射配置相同的路径(例如POST ,在一个和GET 另一个中);将找不到 MVC 映射..
|
跨域资源共享 (CORS) 支持
从 4.2 版开始,您可以使用元素配置<http:inbound-channel-adapter>
and 。它表示与 Spring MVC的注解选项相同,并允许为 Spring Integration HTTP 端点配置跨域资源共享 (CORS):<http:inbound-gateway>
<cross-origin>
@CrossOrigin
@Controller
-
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
bean 中。
响应状态代码
从 4.1 版开始,您可以配置<http:inbound-channel-adapter>
以status-code-expression
覆盖默认200 OK
状态。表达式必须返回一个可以转换为org.springframework.http.HttpStatus
枚举值的对象。有evaluationContext
一个BeanResolver
and,从 5.1 版开始,RequestEntity<?>
作为根对象提供。一个示例可能是在运行时解析一些返回状态代码值的作用域 bean。但是,最有可能的是,它被设置为一个固定值,例如status-code=expression="204"
(无内容)或status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"
. 默认status-code-expression
为空,表示返回正常的“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>
解析“状态代码” 。从 4.2 版本开始,在. 有两种方法可以修改此行为:http_statusCode
Message
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
消息头,如以下示例中所定义:
<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
from URI Template 占位符及其值。 -
#matrixVariables
:Map
根据Spring MVC 规范MultiValueMap
的。请注意,这需要 Spring MVC 3.2 或更高版本。#matrixVariables
-
#requestAttributes
:org.springframework.web.context.request.RequestAttributes
与当前请求关联的。 -
#requestHeaders
:org.springframework.http.HttpHeaders
来自当前请求的对象。 -
#cookies
:来自当前请求Map<String, Cookie>
的实例。javax.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 响应类型,只要其 HTTP 状态为成功(不成功的状态代码会引发异常) ,响应的负载就会Message
包含。ResponseEntity
如果您希望使用不同的类型,例如 a String
,请将其提供为完全限定的类名(java.lang.String
在前面的示例中)。另请参阅有关HTTP Outbound Components中的空响应主体的说明。
从 Spring Integration 2.1 开始,request-timeout HTTP 出站网关的属性被重命名为reply-timeout 以更好地反映其意图。
|
从 Spring Integration 2.2 开始,默认情况下不再启用基于 HTTP 的 Java 序列化。以前,将 但是,由于这可能导致与现有应用程序不兼容,因此决定不再将此转换器自动添加到 HTTP 端点。如果您希望使用 Java 序列化,您可以通过使用属性(当您使用 XML 配置时)或使用方法(在 Java 配置中)将其添加 |
http-method-expression
从 Spring Integration 2.2 开始,您还可以使用 SpEL 和属性动态确定 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"/>
如果要以单向方式使用出站适配器,则可以使用 anoutbound-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 or的实例Expression 。通过在 outbound 的上下文中使用这些表达式,这Map 将提供给URI 变量占位符的进一步解析。
ExpressionEvalMap Message |
重要的
该uriVariablesExpression
属性为评估 URI 变量提供了一种非常强大的机制。我们预计人们大多使用简单的表达方式,例如前面的示例。但是,您也可以配置一些东西,例如"@uriVariablesBean.populate(#root)"
在返回的映射中使用表达式作为variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));
,其中表达式在名为 的消息头中动态提供thing2
。由于标头可能来自不受信任的来源,因此SimpleEvaluationContext
在评估这些表达式时使用 HTTP 出站端点。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()
方法需要 aMultiValueMap<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());
控制 URI 编码
默认情况下,UriComponentsBuilder
在发送请求之前,URL 字符串会被编码(参见 )为 URI 对象。在某些使用非标准 URI(例如 RabbitMQ REST API)的场景中,不希望执行编码。和<http:outbound-gateway/>
提供<http:outbound-channel-adapter/>
一个encoding-mode
属性。要禁用 URL 编码,请将此属性设置为NONE
(默认为TEMPLATE_AND_VALUES
)。如果您希望对某些 URL 进行部分编码,请在 a 中使用expression
a <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 IntegrationFlows.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 IntegrationFlows.from("httpOutRequest")
.handle(Http.outboundGateway("http://localhost:8080/foo")
.httpMethod(HttpMethod.POST)
.expectedResponseType(String.class))
.get();
}
超时处理
在 HTTP 组件的上下文中,必须考虑两个计时区域:
-
与 Spring 集成通道交互时的超时
-
与远程 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
orrest-template
属性,则会实例化默认值RestTemplate
(使用 a )。SimpleClientHttpRequestFactory
对于某些 JVM 实现, 例如,来自 Java™ 平台标准版 6 API 规范 此方法的一些非标准实现可能会忽略指定的超时。要查看连接超时设置,请调用 getConnectTimeout()。 如果你有特定的需求,你应该测试你的超时。考虑使用 |
当您将 Apache HttpComponents HttpClient 与池连接管理器一起使用时,您应该知道,默认情况下,连接管理器为每个给定路由创建不超过两个并发连接,并且总共不超过 20 个连接。对于许多现实世界的应用程序,这些限制可能被证明过于约束。有关配置此重要组件的信息,请参阅Apache 文档。 |
SimpleClientHttpRequestFactory
以下示例使用分别配置为连接和读取超时 5 秒的配置 HTTP 出站网关:
<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 Outbound Gateway,XML Schema 只定义了reply-timeout。回复超时映射到org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler类的sendTimeout属性。更准确地说,属性是在扩展类上设置的,它最终将属性设置在.AbstractReplyProducingMessageHandler
MessagingTemplate
sendTimeout属性的值默认为“-1”,并将应用于已连接的MessageChannel
. 这意味着,根据实现,消息通道的发送方法可能会无限期地阻塞。此外,仅当实际 MessageChannel 实现具有阻塞发送(例如 'full' bounded QueueChannel)时,才使用sendTimeout属性。
HTTP 入站网关
对于 HTTP 入站网关,XML Schema 定义了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
如果您需要对代理配置进行更明确的控制,可以使用 SpringSimpleClientHttpRequestFactory
并配置其“代理”属性,如以下示例所示:
<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 发送多部分 HTTP 请求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