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 受信リクエストを処理するための 2 つのコンポーネント、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 (Javadoc) を導入することで REST サポートを改善しました。この実装は、Spring Framework 3.1 以降で提供される拡張 REST サポートに依存しています。

HTTP 受信・ゲートウェイまたは HTTP 受信・チャネルアダプターの構文解析により、型 IntegrationRequestMappingHandlerMapping (Javadoc) の integrationRequestMappingHandlerMapping Bean が登録されます (まだ登録されていない場合)。HandlerMapping (Javadoc) のこの特定の実装は、そのロジックを RequestMappingInfoHandlerMapping (Javadoc) に委譲します。この実装は、Spring MVCorg.springframework.web.bind.annotation.RequestMapping (Javadoc) アノテーションと同様の機能を提供します。

詳しくは、@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 (Javadoc) のインスタンスを関連付けます。この RequestMapping インスタンスは、次に Spring MVC RequestMappingInfo (Javadoc) に変換されます。

<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 リクエストに基づいて異なるダウンストリームメッセージフローを提供できます。

または、1 つの 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 サーブレットドキュメントまたは Spring Framework Web リアクティブドキュメントを参照してください。

IntegrationRequestMappingHandlerMapping は Spring MVC RequestMappingHandlerMapping クラスを継承し、そのロジックのほとんど、特に handleNoMatch(Set, String, HttpServletRequest) を継承し、何らかの理由でマッピングが一致しない場合に HTTP レスポンスに対して特定の 4xx エラーをスローし、アプリケーションコンテキスト内の残りのマッピングハンドラーの呼び出しを防ぎます。このため、Spring Integration と Spring MVC の両方のリクエストマッピング (たとえば、一方の POST と他方の GET ) に同じパスを設定することはサポートされていません。MVC マッピングが見つかりません ..

クロスオリジンリソースシェアリング(CORS)サポート

バージョン 4.2 以降、<http:inbound-channel-adapter> および <http:inbound-gateway> を <cross-origin> エレメントで構成できます。これは、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 リクエストメソッド: GETPOSTHEADOPTIONSPUTPATCHDELETETRACE ここで指定されたメソッドは、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 から、<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 であり、通常の "200OK " レスポンス状況が戻されることを意味します。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 です。この動作を変更するには 2 つの方法があります。

  • 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 など、ゲートウェイで変換できるものに変換する必要があります。適切な候補は、例外のメッセージプロパティです。これは、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 以降、ペイロードおよびヘッダー式で使用可能な既存の #pathVariables および #requestParams 変数に加えて、他の有用な式変数を追加しました。

  • #requestParamsServletRequest 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="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" 属性が提供されていることに注意してください。これらは、最も一般的に設定される 2 つの値です。デフォルトの 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 シリアライゼーションはデフォルトで有効ではなくなりました。以前は、expected-response-type 属性を Serializable オブジェクトに設定すると、Accept ヘッダーが正しく設定されませんでした。Spring Integration 2.2 以降、SerializingHttpMessageConverter は Accept ヘッダーを application/x-java-serialized-object に設定するように更新されました。

ただし、これにより既存のアプリケーションとの非互換性が発生する可能性があるため、このコンバーターを HTTP エンドポイントに自動的に追加しないことにしました。Java 直列化を使用する場合は、message-converters 属性(XML 構成を使用する場合)または setMessageConverters() メソッド(Java 構成)を使用して、SerializingHttpMessageConverter を適切なエンドポイントに追加できます。または、代わりに JSON を使用することを検討することもできます。JSON は、クラスパスに Jackson ライブラリを含める [GitHub] (英語) ことで有効になります。

Spring Integration 2.2 以降、SpEL と http-method-expression 属性を使用して HTTP メソッドを動的に決定することもできます。この属性は http-method と相互に排他的であることに注意してください。expected-response-type の代わりに expected-response-type-expression 属性を使用して、レスポンスの型を決定する有効な 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" は、Message をルートオブジェクトとして使用する SpEL 式であり、動的 URL を有効にします。式の評価の結果の URL には、引き続き URI 変数のプレースホルダーを含めることができます。

以前のリリースでは、一部のユーザーはプレースホルダーを使用して、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&amp;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 の 2 つの属性を定義します。name 属性は URI 変数の名前を識別し、expression 属性は実際の値を設定するために使用されます。expression 属性を使用すると、メッセージペイロードとメッセージヘッダーへの完全な動的アクセスを提供する Spring 式言語 (SpEL) の機能をフルに活用できます。例: 上記の構成では、Message のペイロードオブジェクトで getZip() メソッドが呼び出され、そのメソッドの結果が 'zipCode' という名前の URI 変数の値として使用されます。

Spring Integration 3.0 以降、HTTP 送信エンドポイントは、評価する必要がある expression を指定する 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 は、送信 Message のコンテキストでそれらの式を使用することにより、URI 変数プレースホルダーのさらなる解決のために ExpressionEvalMap に提供されます。

重要 uriVariablesExpression プロパティは、URI 変数を評価するための非常に強力なメカニズムを提供します。前述の例のような単純な表現を使用することが多いと予想されます。ただし、返されたマップ内の式が variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class))); である "@uriVariablesBean.populate(#root)" などを構成することもできます。この場合、式は thing2 という名前のメッセージヘッダーに動的に提供されます。ヘッダーは信頼できないソースからのものである可能性があるため、HTTP 送信 エンドポイントはこれらの式を評価するときに SimpleEvaluationContext を使用します。SimpleEvaluationContext は SpEL 機能のサブセットのみを使用します。メッセージソースを信頼し、制限された SpEL 構造を使用したい場合は、送信エンドポイントの trustedSpel プロパティを true に設定します。

URL パラメーターを作成およびエンコードするためのカスタム url-expression およびいくつかのユーティリティを使用することにより、メッセージごとに 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&amp;b=B'"/>
</int-http:outbound-gateway>

この場合、URL エンコードを手動で指定する必要があります。例: この目的で org.apache.http.client.utils.URLEncodedUtils#format() を使用できます。前述のように、手動で作成された MultiValueMap<String, String> は、次の Java Streams スニペットを使用して、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 文字列は、リクエストを送信する前に URI オブジェクトにエンコードされます ( UriComponentsBuilder (Javadoc) を参照)。非標準の 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 です。