HTTP 名稱空間支援
Spring Integration 提供了 http
名稱空間以及相應的 schema 定義。要將其包含在配置中,請在應用程式上下文配置檔案中提供以下名稱空間宣告:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http
https://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
...
</beans>
入站
XML 名稱空間提供了用於處理 HTTP 入站請求的兩個元件:inbound-channel-adapter
和 inbound-gateway
。要處理不需要返回專用響應的請求,請使用 inbound-channel-adapter
。以下示例顯示瞭如何配置一個:
<int-http:inbound-channel-adapter id="httpChannelAdapter" channel="requests"
supported-methods="PUT, DELETE"/>
要處理需要響應的請求,請使用 inbound-gateway
。以下示例顯示瞭如何配置一個:
<int-http:inbound-gateway id="inboundGateway"
request-channel="requests"
reply-channel="responses"/>
請求對映支援
Spring Integration 3.0 透過引入 IntegrationRequestMappingHandlerMapping 改進了 REST 支援。該實現依賴於 Spring Framework 3.1 或更高版本提供的增強 REST 支援。 |
對 HTTP 入站閘道器或 HTTP 入站通道介面卡的解析會註冊一個 integrationRequestMappingHandlerMapping
bean,其型別為 IntegrationRequestMappingHandlerMapping
(如果尚未註冊)。HandlerMapping
的這個特定實現將其邏輯委託給 RequestMappingInfoHandlerMapping
。該實現提供了類似於 Spring MVC 中 org.springframework.web.bind.annotation.RequestMapping
註解的功能。
有關更多資訊,請參見 使用 @RequestMapping 對映請求。 |
為此,Spring Integration 3.0 引入了 <request-mapping>
元素。您可以將此可選元素新增到 <http:inbound-channel-adapter>
和 <http:inbound-gateway>
中。它與 path
和 supported-methods
屬性結合使用。以下示例顯示瞭如何在入站閘道器上配置它:
<inbound-gateway id="inboundController"
request-channel="requests"
reply-channel="responses"
path="/foo/{fooId}"
supported-methods="GET"
view-name="foo"
error-code="oops">
<request-mapping headers="User-Agent"
params="myParam=myValue"
consumes="application/json"
produces="!text/plain"/>
</inbound-gateway>
根據前面的配置,名稱空間解析器會建立 IntegrationRequestMappingHandlerMapping
(如果不存在)和 HttpRequestHandlingController
bean 的例項,並將其與 RequestMapping
例項關聯。此 RequestMapping
例項隨後會轉換為 Spring MVC 的 RequestMappingInfo
。
<request-mapping>
元素提供以下屬性:
-
headers
-
params
-
consumes
-
produces
透過 <http:inbound-channel-adapter>
或 <http:inbound-gateway>
的 path
和 supported-methods
屬性,<request-mapping>
屬性直接轉換為 Spring MVC 中 org.springframework.web.bind.annotation.RequestMapping
註解提供的相應選項。
<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 MVC 的 RequestMappingHandlerMapping 類,繼承了其大部分邏輯,特別是 handleNoMatch(Set, String, HttpServletRequest) ,當由於某種原因對映不匹配時,它會為 HTTP 響應丟擲特定的 4xx 錯誤,從而阻止呼叫應用程式上下文中任何剩餘的對映處理器。因此,Spring Integration 和 Spring MVC 請求對映配置相同的 path (例如,一箇中是 POST ,另一箇中是 GET )是不受支援的;MVC 對映將找不到。 |
跨域資源共享 (CORS) 支援
從 4.2 版本開始,您可以使用 <cross-origin>
元素配置 <http:inbound-channel-adapter>
和 <http:inbound-gateway>
。它代表與 Spring MVC @Controller
註解的 @CrossOrigin
相同的選項,並允許為 Spring Integration HTTP 端點配置跨域資源共享 (CORS):
-
origin
:允許的來源列表。*
表示允許所有來源。這些值被放置在預檢響應和實際響應的Access-Control-Allow-Origin
頭中。預設值為*
。 -
allowed-headers
:指示在實際請求期間可以使用哪些請求頭。*
表示允許客戶端請求的所有頭。此屬性控制預檢響應的Access-Control-Allow-Headers
頭的值。預設值為*
。 -
exposed-headers
:使用者代理允許客戶端訪問的響應頭列表。此屬性控制實際響應的Access-Control-Expose-Headers
頭的值。 -
method
:允許的 HTTP 請求方法:GET
、POST
、HEAD
、OPTIONS
、PUT
、PATCH
、DELETE
、TRACE
。此處指定的方法會覆蓋supported-methods
中的方法。 -
allow-credentials
:如果瀏覽器應包含與請求域關聯的任何 cookie,則設定為true
;否則設定為false
。空字串 ("") 表示未定義。如果為true
,則預檢響應包含Access-Control-Allow-Credentials=true
頭。預設值為true
。 -
max-age
:控制預檢響應的快取持續時間。將其設定為合理的值可以減少瀏覽器所需的預檢請求-響應互動次數。此屬性控制預檢響應中Access-Control-Max-Age
頭的值。-1
表示未定義。預設值為 1800 秒(30 分鐘)。
CORS Java 配置由 org.springframework.integration.http.inbound.CrossOrigin
類表示,其例項可以注入到 HttpRequestHandlingEndpointSupport
bean 中。
響應狀態碼
從 4.1 版本開始,您可以使用 status-code-expression
配置 <http:inbound-channel-adapter>
來覆蓋預設的 200 OK
狀態。該表示式必須返回一個可轉換為 org.springframework.http.HttpStatus
列舉值的物件。evaluationContext
具有 BeanResolver
,並且從 5.1 版本開始,將 RequestEntity<?>
作為根物件提供。例如,可以在執行時解析返回狀態碼值的某個作用域 bean。但是,更有可能的是將其設定為固定值,例如 status-code=expression="204"
(No Content),或 status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"
。預設情況下,status-code-expression
為 null,這意味著返回正常的 '200 OK' 響應狀態。使用 RequestEntity<?>
作為根物件,狀態碼可以是有條件的,例如取決於請求方法、某些頭、URI 內容甚至請求體。以下示例顯示瞭如何將狀態碼設定為 ACCEPTED
:
<http:inbound-channel-adapter id="inboundController"
channel="requests" view-name="foo" error-code="oops"
status-code-expression="T(org.springframework.http.HttpStatus).ACCEPTED">
<request-mapping headers="BAR"/>
</http:inbound-channel-adapter>
<http:inbound-gateway>
從回覆 Message
的 http_statusCode
頭解析 '狀態碼'。從 4.2 版本開始,如果在 reply-timeout
內未收到回覆,則預設響應狀態碼為 500 Internal Server Error
。有兩種方法可以修改此行為:
-
新增
reply-timeout-status-code-expression
。這與入站介面卡上的status-code-expression
具有相同的語義。 -
新增
error-channel
並返回帶有 HTTP 狀態碼頭的適當訊息,如下例所示:<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 伺服器錯誤響應狀態,但在某些情況下,問題可能是由不正確的請求引數引起的,因此應該丟擲帶有 4xx 客戶端錯誤狀態的 ResponseStatusException
。有關更多資訊,請參見 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 以來,除了 payload 和 header 表示式中現有的 #pathVariables
和 #requestParams
變數外,我們還添加了其他有用的表示式變數:
-
#requestParams
:來自ServletRequest
parameterMap
的MultiValueMap
。 -
#pathVariables
:來自 URI 模板佔位符及其值的Map
。 -
#matrixVariables
:根據 Spring MVC 規範 的MultiValueMap
的Map
。請注意,#matrixVariables
需要 Spring MVC 3.2 或更高版本。 -
#requestAttributes
:與當前請求關聯的org.springframework.web.context.request.RequestAttributes
。 -
#requestHeaders
:來自當前請求的org.springframework.http.HttpHeaders
物件。 -
#cookies
:來自當前請求的jakarta.servlet.http.Cookie
例項的MultiValueMap<String, 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="https:///test"
http-method="POST"
extract-request-payload="false"
expected-response-type="java.lang.String"
charset="UTF-8"
request-factory="requestFactory"
reply-timeout="1234"
reply-channel="replies"/>
最重要的是,請注意提供了 'http-method' 和 'expected-response-type' 屬性。這是兩個最常配置的值。預設的 http-method
是 POST
,預設的響應型別是 null。如果響應型別為 null,只要 HTTP 狀態碼是成功的(非成功的狀態碼會丟擲異常),回覆 Message
的載荷就會包含 ResponseEntity
。如果您期望其他型別,例如 String
,請以完全限定類名提供(在前面的示例中是 java.lang.String
)。另請參見 HTTP 出站元件 中關於空響應體的注意事項。
從 Spring Integration 2.1 開始,HTTP 出站閘道器的 request-timeout 屬性已重新命名為 reply-timeout ,以便更好地反映其意圖。 |
自 Spring Integration 2.2 以來,預設不再啟用透過 HTTP 進行 Java 序列化。以前,當將 然而,由於這可能導致與現有應用程式不相容,因此決定不再自動將此轉換器新增到 HTTP 端點。如果您希望使用 Java 序列化,可以透過使用 |
從 Spring Integration 2.2 開始,您還可以透過使用 SpEL 和 http-method-expression
屬性動態確定 HTTP 方法。請注意,此屬性與 http-method
互斥。您也可以使用 expected-response-type-expression
屬性代替 expected-response-type
,並提供任何有效的 SpEL 表示式來確定響應的型別。以下配置示例使用 expected-response-type-expression
:
<int-http:outbound-gateway id="example"
request-channel="requests"
url="https:///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="https:///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 Expression Language (SpEL) 的強大功能,該功能使您能夠完全動態地訪問訊息載荷和訊息頭。例如,在前面的配置中,對 Message
的載荷物件呼叫 getZip()
方法,該方法的結果用作名為 'zipCode' 的 URI 變數的值。
自 Spring Integration 3.0 以來,HTTP 出站端點支援 uri-variables-expression
屬性,用於指定一個表示式,該表示式應被求值,從而生成一個包含 URL 模板中所有 URI 變數佔位符的 Map
。它提供了一種機制,您可以在其中根據出站訊息使用不同的變量表達式。此屬性與 <uri-variable/>
元素互斥。以下示例顯示瞭如何使用 uri-variables-expression
屬性:
<int-http:outbound-gateway
url="https://foo.host/{foo}/bars/{bar}"
request-channel="trafficChannel"
http-method="GET"
uri-variables-expression="@uriVariablesBean.populate(payload)"
expected-response-type="java.lang.String"/>
uriVariablesBean
可能定義如下:
public class UriVariablesBean {
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
public Map<String, ?> populate(Object payload) {
Map<String, Object> variables = new HashMap<String, Object>();
if (payload instanceOf String.class)) {
variables.put("foo", "foo"));
}
else {
variables.put("foo", EXPRESSION_PARSER.parseExpression("headers.bar"));
}
return variables;
}
}
uri-variables-expression 必須求值為 Map 。Map 的值必須是 String 或 Expression 的例項。將此 Map 提供給 ExpressionEvalMap ,以便在出站 Message 的上下文中進一步解析 URI 變數佔位符。 |
重要提示 uriVariablesExpression
屬性提供了一種非常強大的機制來評估 URI 變數。我們預計人們主要使用簡單的表示式,例如前面的示例。但是,您也可以配置類似 "@uriVariablesBean.populate(#root)"
的內容,返回的 map 中的表示式可以是 variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));
,其中表達式在名為 thing2
的訊息頭中動態提供。由於頭可能來自不可信的來源,HTTP 出站端點在評估這些表示式時使用 SimpleEvaluationContext
。SimpleEvaluationContext
僅使用 SpEL 特性的一個子集。如果您信任您的訊息來源並希望使用受限的 SpEL 結構,請將出站端點的 trustedSpel
屬性設定為 true
。
您可以使用自定義 url-expression
和一些用於構建和編碼 URL 引數的工具來實現需要按訊息提供動態 URI 變數集的場景。以下示例顯示瞭如何實現:
url-expression="T(org.springframework.web.util.UriComponentsBuilder)
.fromHttpUrl('https://HOST:PORT/PATH')
.queryParams(payload)
.build()
.toUri()"
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()
來達到此目的。如前所述,可以使用以下 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 編碼
預設情況下,在傳送請求之前,URL 字串會被編碼(參見 UriComponentsBuilder
)為 URI 物件。在某些非標準 URI 的場景中(例如 RabbitMQ REST API),進行編碼是不希望的。<http:outbound-gateway/>
和 <http:outbound-channel-adapter/>
提供一個 encoding-mode
屬性。要停用 URL 編碼,請將此屬性設定為 NONE
(預設為 TEMPLATE_AND_VALUES
)。如果您希望部分編碼 URL 的某些部分,請在 <uri-variable/>
中使用 expression
,如下例所示:
<http:outbound-gateway url="https://somehost/%2f/fooApps?bar={param}" encoding-mode="NONE">
<http:uri-variable name="param"
expression="T(org.apache.commons.httpclient.util.URIUtil)
.encodeWithinQuery('Hello World!')"/>
</http:outbound-gateway>
使用 Java DSL,此選項可以透過 BaseHttpMessageHandlerSpec.encodingMode()
選項進行控制。相同的配置也適用於 WebFlux 模組 和 Web 服務模組 中類似的出站元件。對於更復雜的場景,建議在外部提供的 RestTemplate
上配置 UriTemplateHandler
;或者在 WebFlux 的情況下,在 WebClient
上配置其 UriBuilderFactory
。