Spring Integration的HTTP支持

时间:2022-12-09 11:01:47

Spring Integration的HTTP支持

Spring Integration的HTTP支持允许运行HTTP请求和处理入站HTTP请求。 HTTP 支持由以下网关实现组成:和 。 另请参阅 WebFlux 支持​。​​HttpInboundEndpoint​​​​HttpRequestExecutingMessageHandler​

您需要将此依赖项包含在项目中:

<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-http</artifactId>
<version>6.0.0</version>
</dependency>

必须在目标 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 Integration的HTTP支持。

以下示例 Bean 定义了一个 HTTP 入站端点:

<bean 
class="org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway">
<property name="requestChannel" ref="httpRequestChannel" />
<property name="replyChannel" ref="httpReplyChannel" />
</bean>

接受实例列表,否则依赖于默认列表。 转换器允许自定义从 到 的映射。 默认转换器封装了简单的策略,例如,这些策略为内容类型以 开头的请求创建消息。 有关完整详细信息,请参阅 Javadoc。 可以设置一个附加标志 () 以及自定义列表,以在自定义转换器之后添加默认转换器。 默认情况下,此标志设置为 ,这意味着自定义转换器将替换默认列表。​​HttpRequestHandlingMessagingGateway​​​​HttpMessageConverter​​​​HttpServletRequest​​​​Message​​​​String​​​​POST​​​​text​​​​mergeWithDefaultConverters​​​​HttpMessageConverter​​​​false​

消息转换过程使用 (可选) 属性和传入标头。 从版本 4.3 开始,如果请求没有内容类型标头,则假定为 ,如 所建议的那样。 以前,此类消息的正文被忽略。​​requestPayloadType​​​​Content-Type​​​​application/octet-stream​​​​RFC 2616​

Spring Integration 2.0 实现了多部分文件支持。 如果请求已包装为 ,当您使用默认转换器时,该请求将转换为有效负载,该有效负载包含的值可能是字节数组、字符串或 Spring 的实例,具体取决于各个部分的内容类型。​​MultipartHttpServletRequest​​​​Message​​​​MultiValueMap​​​​MultipartFile​

HTTP 入站端点在上下文中定位一个 bean 名称 (与 Spring 的预期名称相同)。 如果它确实找到了该 Bean,则会在入站请求映射器上启用对多部分文件的支持。 否则,当它尝试将多部分文件请求映射到 Spring 集成时,它会失败。 有关 Spring 对 的支持的更多信息,请参阅 Spring 参考手册​。​​MultipartResolver​​​​multipartResolver​​​​DispatcherServlet​​​​Message​​​​MultipartResolver​


如果您希望将 a 代理到另一台服务器,最好将其保留为原始形式。 要处理这种情况,请不要将 Bean 添加到上下文中。 将端点配置为需要请求,自定义消息转换器以包含 ,并禁用默认的多部分转换器。 您可能需要一些其他转换器来回复。 以下示例显示了这样的安排:​​multipart/form-data​​​​multipartResolver​​​​byte[]​​​​ByteArrayHttpMessageConverter​

<int-http:inbound-gateway
channel="receiveChannel"
path="/inboundAdapter.htm"
request-payload-type="byte[]"
message-converters="converters"
merge-with-default-converters="false"
supported-methods="POST" />

<util:list >
<beans:bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<beans:bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</util:list>

向客户端发送响应时,可通过多种方式自定义网关的行为。 默认情况下,网关通过发回状态代码来确认已收到请求。 可以通过提供由Spring MVC解析的“viewName”来自定义此响应。 如果网关需要对 的回复,则可以设置标志(构造函数参数)以使网关在创建 HTTP 响应之前等待回复。 以下示例将网关配置为具有视图名称的 Spring MVC 控制器:​​200​​​​ViewResolver​​​​Message​​​​expectReply​​​​Message​

<bean 
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 方法。​​constructor-arg​​​​true​​​​POST​​​​GET​

回复消息在模型图中可用。 默认情况下,该映射条目的键为“reply”,但您可以通过在端点的配置上设置 “replyKey” 属性来覆盖此默认值。

有效负载验证

从版本 5.2 开始,可以为 HTTP 入站终端节点提供 ,以便在发送到通道之前检查有效负载。 此有效负载已经是转换和提取的结果,以缩小有关有价值数据的验证范围。 验证失败处理与Spring MVC错误处理完全相同。​​Validator​​​​payloadExpression​

HTTP 出站组件

本节介绍 Spring 集成的 HTTP 出站组件。

用​​HttpRequestExecutingMessageHandler​

要配置 ,请编写类似于以下内容的 Bean 定义:​​HttpRequestExecutingMessageHandler​

<bean 
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 
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 客户端的使用也支持通过 ,您可以注入该客户端(如前所示)。​​SimpleClientHttpRequestFactory​​​​HttpURLConnection​​​​CommonsClientHttpRequestFactory​

对于出站网关,网关生成的回复消息包含请求消息中存在的所有消息标头。

使用饼干

基本 Cookie 支持由出站网关上的属性提供。 设置为 (默认值为 ) 时,在响应中从服务器接收的标头将转换为回复消息中的标头。 然后,此标头将用于后续发送。 这样可以实现简单的有状态交互,如下所示:​​transfer-cookies​​​​true​​​​false​​​​Set-Cookie​​​​Cookie​

​…→logonGateway→…→doWorkGateway→…→logoffGateway→…​

如果是,则收到的任何标头都保持与回复消息中一样,并在后续发送时删除。​​transfer-cookies​​​​false​​​​Set-Cookie​​​​Set-Cookie​

空响应正文


HTTP 是一种请求-响应协议。 但是,响应可能没有正文,只有标头。 在这种情况下,生成的回复有效负载为 ,无论提供任何 . 根据 HTTP RFC 状态代码定义​,有许多状态要求响应不得包含消息正文(例如,)。 在某些情况下,对同一 URL 的调用可能会也可能不会返回响应正文。 例如,对 HTTP 资源的第一个请求返回内容,但第二个请求不返回内容(返回 )。 但是,在所有情况下,都会填充邮件头。 这可以在 HTTP 出站网关之后的某些路由逻辑中使用。 您还可以使用“有效负载类型路由器/>”<将带有 a 的消息路由到与用于正文响应的消息不同的流。​​HttpRequestExecutingMessageHandler​​​​Message​​​​org.springframework.http.ResponseEntity​​​​expected-response-type​​​​204 No Content​​​​304 Not Modified​​​​http_statusCode​​​​ResponseEntity​


预期响应类型


除了前面关于空响应正文的说明之外,如果响应确实包含正文,则必须提供适当的属性,否则再次收到没有正文的属性。 必须与响应中的(已配置或默认)实例和标头兼容。 这可以是抽象类,甚至可以是接口(例如,当您使用 Java 序列化和 时)。​​expected-response-type​​​​ResponseEntity​​​​expected-response-type​​​​HttpMessageConverter​​​​Content-Type​​​​java.io.Serializable​​​​Content-Type: application/x-java-serialized-object​


从版本 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  channel="requests"
supported-methods="PUT, DELETE"/>

要处理需要响应的请求,请使用 . 以下示例演示如何配置一个:​​inbound-gateway​

<int-http:inbound-gateway 
request-channel="requests"
reply-channel="responses"/>

请求映射支持

Spring Integration 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 
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,并与其关联 RequestMap 的实例。 反过来,这个实例被转换为Spring MVC RequestMappingInfo。​​IntegrationRequestMappingHandlerMapping​​​​HttpRequestHandlingController​​​​RequestMapping​

该元素提供以下属性:​​<request-mapping>​

  • ​headers​
  • ​params​
  • ​consumes​
  • ​produces​

使用 或 的 and 属性,属性直接转换为 Spring MVC 中的注释提供的相应选项。​​path​​​​supported-methods​​​​<http:inbound-channel-adapter>​​​​<http:inbound-gateway>​​​​<request-mapping>​​​​org.springframework.web.bind.annotation.RequestMapping​

该元素允许您将多个 Spring Integration 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类,继承了它的大部分逻辑,特别是当映射由于某种原因不匹配时,它会为HTTP响应抛出特定的错误,从而阻止调用应用程序上下文中任何剩余的映射处理程序。 出于这个原因,为Spring Integration和Spring MVC请求映射配置相同的路径(例如 在一个和另一个)不受支持;将找不到 MVC 映射。.​​IntegrationRequestMappingHandlerMapping​​​​RequestMappingHandlerMapping​​​​handleNoMatch(Set, String, HttpServletRequest)​​​​4xx​​​​POST​​​​GET​

跨源资源共享 (CORS) 支持

从版本 4.2 开始,您可以配置 和 with 元素。 它代表了与Spring MVC相同的注释选项,并允许为Spring Integration HTTP端点配置跨源资源共享(CORS):​​<http:inbound-channel-adapter>​​​​<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 请求方法:、、、、。 此处指定的方法将覆盖 中的方法。GETPOSTHEADOPTIONSPUTPATCHDELETETRACEsupported-methods
  • ​allow-credentials​​:设置为浏览器是否应包含与请求域关联的任何 Cookie,或者是否应包含。 空字符串 (“”) 表示未定义。 如果 ,则预检响应包括标头。 默认值为 。truefalsetrueAccess-Control-Allow-Credentials=truetrue
  • ​max-age​​:控制预检响应的缓存持续时间。 将此值设置为合理的值可以减少浏览器所需的预检请求-响应交互次数。 此属性控制预检响应中标头的值。 值 表示未定义。 默认值为 1800 秒(30 分钟)。Access-Control-Max-Age-1

CORS Java 配置由类表示,类的实例可以注入到 bean 中。​​org.springframework.integration.http.inbound.CrossOrigin​​​​HttpRequestHandlingEndpointSupport​

响应状态代码

从版本 4.1 开始,您可以使用 配置 以覆盖默认状态。 表达式必须返回可转换为枚举值的对象。 从版本 5.1 开始,具有 and 与 as 根对象一起提供。 例如,在运行时解析某个返回状态代码值的作用域 Bean。 但是,它很可能设置为固定值,例如(无内容)或 . 默认情况下,为 null,表示返回正常的“200 OK”响应状态。 使用 as 根对象,状态代码可以是有条件的,例如在请求方法、某些标头、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 
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-expressionstatus-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>

的有效负载为 . 必须将其转换为可由网关转换的内容,例如 . 一个很好的候选项是异常的消息属性,它是使用该技术时使用的值。​​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 客户端错误状态的 。 有关详细信息,请参阅。 发送到此错误通道包含原始异常作为分析的有效负载。 ==== URI 模板变量和表达式​​ResponseStatusException​​​​ResponseStatusException​​​​ErrorMessage​

通过将属性与属性和元素结合使用,可以高度灵活地映射入站请求数据。​​path​​​​payload-expression​​​​header​

在以下示例配置中,入站通道适配器配置为使用以下 URI 接受请求:

/first-name/{firstName}/last-name/{lastName}

使用该属性时,URI 模板变量映射到有效负载,而 URI 模板变量映射到消息头,如以下示例中所定义:​​payload-expression​​​​{firstName}​​​​Message​​​​{lastName}​​​​lname​

<int-http:inbound-channel-adapter 
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​​:来自 .MultiValueMapServletRequestparameterMap
  • ​#pathVariables​​:来自 URI 模板占位符及其值。Map
  • ​#matrixVariables​​:根据Spring MVC规范。 请注意,这需要 Spring MVC 3.2 或更高版本。MapMultiValueMap#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 
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”和“预期响应类型”属性。 这是两个最常配置的值。 默认值为 ,默认响应类型为 null。 对于 null 响应类型,只要其 HTTP 状态为成功(不成功状态代码会引发异常),回复的有效负载就会包含 。 如果需要其他类型(如 ),请将其作为完全限定的类名(在前面的示例中)。 另请参阅有关 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 开始,现在已经更新为将标头设置为 .​​expected-response-type​​​​Serializable​​​​Accept​​​​SerializingHttpMessageConverter​​​​Accept​​​​application/x-java-serialized-object​



但是,由于这可能会导致与现有应用程序不兼容,因此决定不再自动将此转换器添加到 HTTP 终结点。 如果要使用 Java 序列化,可以通过使用属性(使用 XML 配置时)或使用方法(在 Java 配置中)将 添加到相应的端点。 或者,您可能希望考虑改用 JSON,这是通过在类路径上安装 Jackson 库​来实现的。​​SerializingHttpMessageConverter​​​​message-converters​​​​setMessageConverters()​


从 Spring Integration 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 
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 
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-expression”属性。 “url”属性采用一个简单的字符串(带有 URI 变量的占位符,如下所述)。 “url-expression”是一个 SpEL 表达式,将 作为根对象,它启用动态 url。 表达式计算生成的 URL 仍可以具有 URI 变量的占位符。​​Message​



在以前的版本中,某些用户使用占位符将整个 URL 替换为 URI 变量。 Spring 3.1 中的更改可能会导致转义字符出现一些问题,例如“?”。 因此,如果您希望完全在运行时生成 URL,我们建议使用“url-expression”属性。


映射 URI 变量

如果 URL 包含 URI 变量,则可以使用该元素映射它们。 此元素可用于 HTTP 出站网关和 HTTP 出站通道适配器。 下面的示例将 URI 变量映射到表达式:​​uri-variable​​​​zipCode​

<int-http:outbound-gateway 
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) 的全部功能,它使您可以完全动态地访问消息有效负载和消息标头。 例如,在前面的配置中,该方法在 的有效负载对象上调用,该方法的结果用作名为“zipCode”的 URI 变量的值。​​uri-variable​​​​name​​​​expression​​​​name​​​​expression​​​​expression​​​​getZip()​​​​Message​

从 Spring Integration 3.0 开始,HTTP 出站端点支持该属性来指定应评估的 ,从而在 URL 模板中生成所有 URI 变量占位符。 它提供了一种机制,您可以在其中根据出站消息使用不同的变量表达式。 此属性与元素互斥。 下面的示例演示如何使用该属性:​​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  request-channel="testChannel"
url="http://testServer/test?{queryString}">
<int-http:uri-variable name="queryString" expression="'a=A&b=B'"/>
</int-http:outbound-gateway>

在这种情况下,您必须手动提供 URL 编码。 例如,您可以将 用于此目的。 如前所述,可以使用以下 Java Streams 代码段将手动构建转换为方法参数:​​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)的情况下,不希望执行编码。 和 提供一个属性。 要禁用对 URL 进行编码,请将此属性设置为 (默认情况下为 )。 如果要对 URL 的某些部分进行部分编码,请使用 in ,如以下示例所示:​​<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 配置入站网关:

例 1.使用 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 配置入站网关:

例 2.使用 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 配置出站网关:

例 3.使用 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 配置出站网关:

例 4.使用 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 响应的回复通道(使用回复超时)接收回复消息。 下图提供了直观的说明:

Spring Integration的HTTP支持

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

Spring Integration的HTTP支持

在使用 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 实现,类对超时的处理可能不一致。​​URLConnection​



例如,从Java™平台,标准版6 API规范:​​setConnectTimeout​



此方法的某些非标准实现可能会忽略指定的超时。 要查看集合,请致电getConnectTimeout()。​​connect timeout​



如果您有特定需求,则应测试超时。 考虑使用 ,而 反过来,它使用 Apache HttpComponents HttpClient​,而不是依赖于 JVM 提供的实现。​​HttpComponentsClientHttpRequestFactory​


将 Apache HttpComponents HttpClient 与池连接管理器一起使用时,应注意,默认情况下,连接管理器为每个给定路由创建的并发连接不超过两个,总共不超过 20 个连接。 对于许多实际应用,这些限制可能被证明过于严格。 有关配置此重要组件的信息,请参阅 Apache 文档。

以下示例使用 配置了连接超时和读取超时分别为 5 秒的 来配置 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
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 实现具有阻塞发送(例如“full”有界的 QueueChannel)时,才会使用 sendTimeout 属性。​​MessageChannel​

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​​:应绕过代理直接访问的主机列表。 这是一个由 分隔的模式列表。 模式可能以 for 通配符开头或结尾。 与这些模式之一匹配的任何主机都通过直接连接而不是通过代理访问。|*

对于 HTTPS,可以使用以下属性:

  • ​https.proxyHost​​:代理服务器的主机名。
  • ​https.proxyPort​​:端口号,默认值为 80。

有关详细信息,请参阅 https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html

春天的​​SimpleClientHttpRequestFactory​

如果您需要对代理配置进行更明确的控制,则可以使用 Spring 并配置其“代理”属性,如以下示例所示:​​SimpleClientHttpRequestFactory​

<bean 
class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="proxy">
<bean 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 
url="http://localhost/test2"
mapped-request-headers="thing1, thing2"
mapped-response-headers="X-*, HTTP_RESPONSE_HEADERS"
channel="someChannel"/>

<int-http:outbound-channel-adapter
url="http://localhost/test2"
mapped-request-headers="thing1, thing2, HTTP_REQUEST_HEADERS"
channel="someChannel"/>

适配器和网关使用 ,它现在为入站和出站适配器提供了两种静态工厂方法,以便可以应用正确的方向(根据需要将 HTTP 请求和响应映射入或映射出)。​​DefaultHttpHeaderMapper​

如果需要进一步自定义,还可以单独配置 ,并通过属性将其注入适配器。​​DefaultHttpHeaderMapper​​​​header-mapper​

在 5.0 版之前,用户定义的非标准 HTTP 标头的默认前缀为 。 版本 5.0 将默认前缀更改为空字符串。 根据 RFC-6648,现在不鼓励使用此类前缀。 您仍可以通过设置属性来自定义此选项。 以下示例为 HTTP 网关配置标头映射器:​​DefaultHttpHeaderMapper​​​​X-​​​​DefaultHttpHeaderMapper.setUserDefinedHeaderPrefix()​

<int-http:outbound-gateway 
url="http://localhost/test2"
header-mapper="headerMapper"
channel="someChannel"/>

<bean 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 模块提供了一个配置类注释和一个 XML 元素,以将其公开为 REST 服务。 有关详细信息,请参阅集成图。​​@EnableIntegrationGraphController​​​​<int-http:graph-controller/>​​​​IntegrationGraphServer​

HTTP 示例

本节通过几个示例结束了我们对 Spring 集成的 HTTP 支持的介绍。

多部分 HTTP 请求 — RestTemplate(客户端)和 HTTP 入站网关(服务器)

这个例子展示了使用 Spring 发送多部分 HTTP 请求并使用 Spring Integration HTTP 入站适配器接收它是多么简单。 我们创建一个并用多部分数据填充它。 通过将其转换为 . 此特定客户端发送包含公司名称和图像文件(公司徽标)的多部分 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 
channel="receiveChannel"
path="/inboundAdapter.htm"
supported-methods="GET, POST"/>

<int:channel />

<int:service-activator input-channel="receiveChannel">
<bean class="org.springframework.integration.samples.multipart.MultipartReceiver"/>
</int:service-activator>

<bean
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