HTTP リスナーリファレンス - Mule 4

HTTP リスナーは、HTTP サーバーをセットアップして、HTTP 要求を受信したらフローをトリガーできるようにするイベント取得元です。

ソースが受け入れるメソッド (GET、POST、メソッドのリストなど) や、要求を受け入れるパスを選択できるため、さまざまなフローを使用した要求の転送が可能になります。

要求がリスナーによって受け入れられると、対応するフローが HTTP 本文をペイロード、HTTP データを属性 (ヘッダー、クエリパラメーターなど) としてトリガーされます。

HTTP リスナーでは、フローの実行終了後、実行が成功かどうかに基づいて HTTP 応答をカスタマイズできます。たとえば、異なる状況コードを返すことができます。

HTTP リスナー設定

HTTP リスナーを使用するには、設定と対応する接続を宣言する必要があります。この宣言により、要求をリスンする HTTP サーバーが確立されます。

さらに、ベースパスを設定してすべてのリスナーに適用できます。

<http:listener-config name="HTTP_Listener_config" basePath="api/v1">
  <http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>

HTTP リスナー接続

この接続では、サーバーがセットアップされるホストとポート、および使用するプロトコル (通常の接続には HTTP、TLS 接続には HTTPS) が定義されます。

HTTPS を介したセキュアな接続を可能にするには、接続に TLS コンテキストを定義し、サーバーのキーストアを指定する必要があります。相互認証が必要な場合は トラストストアも指定する必要があります。詳細は、​「TLS Configuration」​ (TLS 設定) を参照してください。

<http:listener-connection host="0.0.0.0" port="8081" protocol="HTTPS">
  <tls:context>
    <tls:trust-store path="keystore.jks" password="MyP455W0rD"/>
  </tls:context>
</http:listener-connection>
=== プロジェクトを CloudHub にデプロイするには、ホストを ​0.0.0.0​ に設定する必要があります。これにより、マシン上のすべてのインターフェース上でリスンするための接続がセットアップされます。

テスト目的でローカルにデプロイする場合は、ホストを ​localhost​ に設定することをお勧めします。そうすることで、ローカルに生成された要求のみが受信され、アプリケーションが外部の脅威から攻撃を受けにくくなります。 ===

より高度な設定では、接続が永続的かどうかも定義できます。永続的ではない場合、タイムアウトが設定されます。

HTTP Listener (HTTP リスナー)

HTTP リスナーは、フロー内のイベント取得元として設定され、使用する設定と、要求をリスンするパスを参照する必要があります。

<flow name="http-triggered-flow">
  <http:listener path="/" config-ref="HTTP_Listener_config"/>
  <set-payload value="Help! I've been triggered!"/>
</flow>

HTTP 要求がリスナーと一致すると、その要求データを使用してフローがトリガーされます。本文はペイロードとして設定され、要求行からヘッダーまでその他すべてのデータは属性として反映されます。 トリガーされたフローが完了すると、HTTP リスナーはその結果を使用して適切な HTTP 応答を生成します。

パス

HTTP リスナーのパスは、静的 (完全一致が必要) にすることも、機能のプレースホルダーにすることもできます。プレースホルダーは、ワイルドカード (​*​) (比較対象の一部または全部と一致) にすることも、パラメーター (​{param}​) (一部または全部と一致するだけでなく、URI パラメーターマップ上のそれらの値も取得) にすることもできます。

次のパスの例では、3 つのリスナーが ​api/v1​ を確立する設定をベースパスとして使用しています。

  • account/mulesoft/main-contact​: パス要求 ​http://awesome-company.com/api/v1/account/mulesoft/main-contact​ とのみ完全一致します。

  • account/{accountId}/main-contact​: 類似の構造を持つすべてのパス要求 (​http://awesome-company.com/api/v1/account/salesforce/main-contact​ など) と一致し、​salesforce​ を ​accountId​ の値として保存します。

  • account/{accountId}/*​: main-contact​ とは異なるすべてのパス要求 (​http://awesome-company.com/api/v1/account/mulesoft/users​ など) と一致し、​mulesoft​ を ​accountId​ の値として保存します。

パスの末尾にワイルドカードを使用すると、未処理のリソースへの要求を取得してより適切なエラーメッセージを表示するのに役立ちます。

複数のリスナーが定義されている場合、要求は常に最も具体的なリスナーに転送されます。そのため、前の例では ​accountId: mulesoft​ とサフィックス ​main-contact​ を含む要求は最初のリスナーで処理され、異なる ​accountId​ 値を含む要求は、3 番目ではなく 2 番目のリスナーによって処理されます。

メソッドについて

要求は、受信した HTTP メソッドに基づいて転送することもできます。デフォルトでは、リスナーはすべてのメソッドを処理しますが、これらを選択したメソッド (カスタムメソッドを含む) に制限できます。次の例では、​GET​、​POST​、および ​PUT​ 要求は異なるフローに転送されます。 これは、データの表示を制限する場合に便利です。特定のユーザーにデータの表示を許可し、数人のユーザーにのみ変更を許可することができます。

<flow name="main-contact-write">
  <http:listener path="account/{accountId}/main-contact" allowedMethods="POST, PUT" config-ref="HTTP_Listener_config"/>
  <!-- validate user permissions -->
  <!-- store or update main contact for accountId -->
</flow>

<flow name="main-contact-read">
  <http:listener path="account/{accountId}/main-contact" allowedMethods="GET" config-ref="HTTP_Listener_config"/>
  <!-- fetch main contact for accountId -->
</flow>

<flow name="main-contact-general">
  <http:listener path="account/{accountId}/main-contact" config-ref="HTTP_Listener_config"/>
  <set-payload value="#['The main contact resource does not support ' ++ attributes.method ++ ' requests.']"
</flow>

複数のリスナーが定義されている場合、要求はメソッドと最初に一致したリスナーに転送されるため、デフォルトのリスナーは常に最後に定義する必要があります。

HTTP 要求から Mule メッセージへ

メソッド、要求パス、クエリ、および URI パラメーターなど HTTP 要求行からのデータとヘッダーはすべてトリガーされたフロー内で属性として使用できます。 一方、本文と ​Content-Type​ ヘッダーは、ペイロードとその MIME タイプのセットアップに使用されます。これにより、他のコンポーネントがペイロードの MIME タイプを検査できます。たとえば、DataWeave では HTTP ペイロードを使用するのに入力情報を必要としません。 さらに、​X-Correlation-ID​ または ​MULE_CORRELATION_ID​ (Mule 3 との相互運用目的) ヘッダーが存在する場合、トレーサビリティ目的でメッセージの相関関係 ID の設定に使用されます。

次の HTTP 要求を考えてみます。

POST api/v1/account/salesforce/main-contact?overwrite=true&notify=jane.doe&notify=admin HTTP/1.1
Host: localhost:8081
Content-Type: application/json
Content-Length: 166
X-Correlation-ID: 9cf32672-4f0b-4e8b-b988-40c13aae85b4

{
  "name": "John",
  "surname": "Doe",
  "role": "Senior Vice President",
  "organization": "Marketing",
  "phone": 701222369,
  "email": "john.doe@salesforce.com"
}

メッセージの相関関係 ID は ​9cf32672-4f0b-4e8b-b988-40c13aae85b4​ で、そのペイロードは次の JSON です。

{
  "name": "John",
  "surname": "Doe",
  "role": "Senior Vice President",
  "organization": "Marketing",
  "phone": 701222369,
  "email": "john.doe@salesforce.com"
}

#[payload.name ' ' payload.surname]​ のような式は ​John Doe​ を返します。これは、DataWeave が正しく JSON データを解釈しているためです。

メッセージには以下のような属性があります。

  • method: POST

  • listenerPath: api/v1/account/{accountId}/main-contact

  • requestPath: api/v1/account/salesforce/main-contact

  • relativePath: account/salesforce/main-contact

  • queryParams: エントリ ​overwrite ⇒ true​、​notify ⇒ jane.doe​、​notify ⇒ admin​ を含む、マルチマップ

  • uriParams: accountId ⇒ salesforce​ を含むマップ

  • headers: エントリ​host ⇒ localhost:8081​、​content-type ⇒ application/json​、​content-length ⇒ 166​、​x-correlation-id ⇒ 9cf32672-4f0b-4e8b-b988-40c13aae85b4​ を含むマルチマップ

マルチマップは、特定のキーに対して複数の値が許可される点を除き、マップと似ています。単一値セレクター (​.​) の使用時は最初の値を返しますが、複数値セレクター (​.*​) の使用時はすべての値の取得が許可されます。

#['Received a ' attributes.method ' request for account ' attributes.uriParams.accountId '. The following users are notified: ' ++ (attributes.queryParams.*notify joinBy ', ')]​ のような式は ​Received a POST request for account salesforce. The following users are notified: admin, jane.doe​ を返します。

全 HTTP 要求属性の詳細なリストについては、​HTTP ドキュメントリファレンス​を参照してください。

マルチパートフォームの例

次の例は、HTML フォームを受信したときの HTTP リスナーイベント取得元メッセージの操作を示します。

<form action="http://server.com/cgi/handle"
        enctype="multipart/form-data"
        method="post">

    How would you like to identify the logo? <INPUT type="text" name="name"><BR>
    Which is the logo file? <INPUT type="file" name="logo"><BR>
    What is the main color in the logo? <INPUT type="text" name="color"><BR>
    <INPUT type="submit" value="Send"> <INPUT type="reset">

</form>

フォーム送信時に生成された HTTP 要求はマルチパートになります。

POST /api/v1/account/mulesoft/logo HTTP/1.1
Content-Type: multipart/form-data; boundary=489691234097965980223899
Host: localhost:8081
content-length: 34332

--489691234097965980223899
Content-Disposition: form-data; name="name"

Corporate Logo
--489691234097965980223899
Content-Disposition: form-data; name="logo"; filename="MuleSoft_logo.png"
Content-Type: image/png

.PNG
.
...
IHDR.......L......~.....	pHYs...#...#.x.?v.. .IDATx....q.W.6.....~".N....t....t..#.....LD0T.CF0b..:.3......Q..@...q]U*y\c....
....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%
.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....V"H....`%.$....^6.......|..P.....IEND.B`.
--489691234097965980223899
Content-Disposition: form-data; name="color"

blue
--489691234097965980223899--

各項目は ​parts​ オブジェクトを使用して名前または項目番号でアクセスできます。たとえば、2 つ目のパートは ​payload.parts.logo​ または ​payload.parts[1]​ でアクセスできます。 後者は、名前が指定されない場合に便利です。 各パート内で、そのコンテンツとヘッダーにアクセスできます。たとえば、​payload.parts.color.content​ は ​blue​ を返し、​payload.parts.logo.headers.'Content-Type'​ は ​application/png​ を返します。 非常に一般的なシナリオは、パートのファイル名の取得です。そのため、​Content-Disposition​ ヘッダーは解析されて ​payload.parts.logo.headers.'Content-Disposition'.filename​ のような式を許可します。この場合は ​MuleSoft_logo.png​ が返されます。

マルチパートコンテンツの読み取りと書き込みについての詳細は、​「DataWeave でサポートされる形式」​を参照してください。

HTTP 応答について

トリガーされたフローの実行が完了すると、結果が返されてリスナーは応答を提供できるようになります。フローが正常に実行された場合は通常の応答が返されますが、フローがエラーで終了した場合はエラー応答が返されます。 デフォルトでは、通常の応答は 200 状況コードと共に本文としてメッセージペイロードを返し、エラー応答は 500 状況コードと共に本文としてフローエラーの説明を返します。これらの応答は次の情報を指定することでカスタマイズできます。

  • 状況コード

  • 理由を示す語句

  • ヘッダーマルチマップ

  • 本文

DataWeave を使用して各パラメーターを生成でき、変数を使用してフローからデータを反映できます。

次の例では、アカウントのロゴを保存するためのエンドポイントが定義されます。

  1. 正常に保存されると、​201 Created​ が ​Corporate Logo has been stored as a MuleSoft logo​ などの本文と一緒に返されます。

  2. 保存に失敗すると、状況コードは ​errorCode​ 変数 (使用可能な場合) で定義されるか、デフォルトで ​500​ になります。

  3. カスタムヘッダーも追加されます (​X-Time​)。

  4. 本文 (​Corporate Logo could not be stored​ など) が返されます。

  5. たとえば、ロゴの保存時に ​CONNECTIVITY​ エラーがある場合、返される状況コードは ​504​、他のエラーはすべて ​500​ になります。

エラー応答の理由を示す語句が定義されていないと、コネクタは状況コードに基づいて定義を試みます。そのため、上記で説明したシナリオでは ​Gateway Timeout​ または ​Internal Server Error​ が返されます。
<flow name="store-logo">
  <http:listener config-ref="HTTP_Listener_config" path="/account/{accountId}/logo">
    <http:response statusCode="201" reasonPhrase="Created"> // 1
      <http:body ><![CDATA[#[output text/plain --- vars.logoName ++ ' has been stored as a ' ++ vars.accountId ++ ' logo.']]]></http:body>
    </http:response>
    <http:error-response statusCode="#[vars.errorCode default 500]"> // 2
      <http:body ><![CDATA[#[vars.logoName ++ ' could not be stored.']]]></http:body> // 3
      <http:headers ><![CDATA[#[
        output application/java
        ---
        {
          "X-Time" : "50s" // 4
        }
      ]]]></http:headers>
    </http:error-response>
  </http:listener>
  <set-variable variableName="logoName" value="#[payload.parts.name.content]"
  mimeType="text/plain"/>
  <set-variable variableName="accountId" value="#[attributes.uriParams.accountId]"
  mimeType="text/plain"/>
  <!-- store logo -->
  <error-handler >
    <on-error-propagate type="CONNECTIVITY"> // 5
      <set-variable variableName="errorCode" value="504"/>
    </on-error-propagate>
  </error-handler>
</flow>

HTTP ストリーミングモード

応答本文の処理時、HTTP Connector は、送信するデータのサイズが明らかではない場合はデータの種類を考慮し、​chunked​ エンコードを使用します (サイズ情報のないストリームとみなす)。この動作は、​responseStreamingMode​ オプションを使用して変更できます。

  • AUTO (自動) (デフォルト): 本文のサイズが定義されている場合、リスナーは ​Content-Length​ エンコードを使用します。それ以外の場合は ​Transfer-Encoding: chunked​ を使用します。

  • ALWAYS (常時): 存在するサイズデータに関係なく ​Transfer-Encoding: chunked​ を使用します。

  • NEVER (なし): Content-Length​ エンコードを使用し、必要に応じてストリームをコンシュームしてデータサイズを判定します。

次の例では、アカウントの主連絡先は常に ​Content-Length​ エンコードを使用して返されます。

<flow name="main-contact-read">
  <http:listener path="account/{accountId}/main-contact" allowedMethods="GET" responseStreamingMode="NEVER" config-ref="HTTP_Listener_config"/>
  <!-- fetch main contact for accountId -->
</flow>