第10章 Undertow
10.1. Undertow ハンドラーについて リンクのコピーリンクがクリップボードにコピーされました!
Undertow は、ブロックタスクと非ブロックタスクの両方に使用するよう設計された Web サーバーです。JBoss EAP 7 では JBoss Web は Undertow に置き換わります。主な機能の一部は以下のとおりです。
- ハイパフォーマンス
- 組み込み可能
- Servlet 3.1
- Web ソケット
- リバースプロキシー
リクエストライフサイクル
クライアントがサーバーに接続するときに、Undertow によって io.undertow.server.HttpServerConnection が作成されます。クライアントがリクエストを送信するときに、リクエストは Undertow パーサーによって解析され、生成される io.undertow.server.HttpServerExchange はルートハンドラーに渡されます。ルートハンドラーが完了すると、以下の 4 つのいずれかのことが起こります。
- 交換が完了する
- リクエストチャネルと応答チャネルが完全に読み取られたり、書き込まれた場合に、交換が完了したと見なされます。リクエスト側は、GET や HEAD などのコンテンツがないリクエストの場合に、自動的に完全に読み取られたと見なされます。読み取り側は、ハンドラーが完全な応答を書き込み、応答チャネルを閉じ、応答チャネルを完全にフラッシュしたときに、完了したと見なされます。交換がすでに完了した場合は、どんなアクションも行われません。
- 交換を完了せずにルートハンドラーが通常どおり返される
-
この場合、交換は
HttpServerExchange.endExchange()を呼び出して完了します。 - ルートハンドラーが例外で返される
-
この場合、
500の応答コードが設定され、HttpServerExchange.endExchange()を使用して交換が終了します。 - ルートハンドラーは、
HttpServerExchange.dispatch()が呼び出された後、または非同期 IO が開始された後に返されることがあります。 - この場合、ディスパッチされたタスクはディスパッチエグゼキューターに送信されます。また、非同期 IO がリクエストチャネルまたは応答チャネルのいずれかで開始された場合は、このタスクが開始されます。この場合、交換は完了しません。非同期タスクによって、処理が完了したときに交換が完了します。
HttpServerExchange.dispatch() の最も一般的な使用方法は、ワーカースレッドに対してブロックが許可されない IO スレッドから実行を移動することです (この結果、ブロック操作が許可されます)。このパターンは通常以下のようになります。
ワーカースレッドへのディスパッチ:
public void handleRequest(final HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
//handler code
}
交換は呼び出しスタックが返されるまで実際にはディスパッチされないため、交換で一度に複数のスレッドがアクティブにならないようにすることができます。交換はスレッドセーフではありません。ただし、交換は、両方のスレッドが一度に変更しようとしない限り、複数のスレッド間で渡すことができます。
交換の終了
交換を終了するには、リクエストチャネルを読み取り、応答チャネルで shutdownWrites() を呼び出し、フラッシュする方法と HttpServerExchange.endExchange() を呼び出す方法の 2 つがあります。endExchange() が呼び出された場合、Undertow はコンテンツが生成されたかどうかを確認します。生成された場合、Undertow はリクエストチャネルを単にドレインし、応答チャネルを閉じ、フラッシュします。生成されず、交換で登録されたデフォルトの応答リスナーがある場合は、Undertow によってそれらの各応答リスナーがデフォルトの応答を生成できるようになります。このメカニズムにより、デフォルトのエラーページが生成されます。
Undertow の詳細については、JBoss EAP Configuration Guide の Configuring the Web Server を参照してください。
10.2. デプロイメントでの既存の Undertow ハンドラーの使用 リンクのコピーリンクがクリップボードにコピーされました!
Undertow は、JBoss EAP にデプロイされたアプリケーションで使用できるハンドラーのデフォルトセットを提供します。利用可能なハンドラーとその属性の完全なリストはここで確認できます。
デプロイメントでハンドラーを使用するには、WEB-INF/undertow-handlers.conf ファイルを追加する必要があります。
WEB-INF/undertow-handlers.conf の例
allowed-methods(methods='GET')
すべてのハンドラーでは、特定のケースでそのハンドラーを適用するためにオプションの述語を指定することもできます。
オプションの述語がある WEB-INF/undertow-handlers.conf の例
path('/my-path') -> allowed-methods(methods='GET')
上記の例では、allowed-methods ハンドラーのみがパス /my-path に適用されます。
一部のハンドラーにはデフォルトのパラメーターがあり、名前を使用せずにハンドラー定義でそのパラメーターの値を指定できます。
デフォルトのパラメーターを使用した WEB-INF/undertow-handlers.conf の例
path('/a') -> redirect('/b')
また、WEB-INF/jboss-web.xml ファイルを更新して 1 つまたは複数のハンドラーの定義を含めることもできます (ただし、WEB-INF/undertow-handlers.conf を使用することが推奨されます)。
WEB-INF/jboss-web.xml の例
<jboss-web>
<http-handler>
<class-name>io.undertow.server.handlers.AllowedMethodsHandler</class-name>
<param>
<param-name>methods</param-name>
<param-value>GET</param-value>
</param>
</http-handler>
</jboss-web>
提供された Undertow ハンドラーの完全なリストは、ここで確認できます。
10.3. カスタムハンドラーの作成 リンクのコピーリンクがクリップボードにコピーされました!
-
カスタムハンドラーは
WEB-INF/jboss-web.xmlファイルで定義できます。
<jboss-web>
<http-handler>
<class-name>org.jboss.example.MyHttpHandler</class-name>
</http-handler>
</jboss-web>
ハンドラークラスの例:
package org.jboss.example;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
public class MyHttpHandler implements HttpHandler {
private HttpHandler next;
public MyHttpHandler(HttpHandler next) {
this.next = next;
}
public void handleRequest(HttpServerExchange exchange) throws Exception {
// do something
next.handleRequest(exchange);
}
}
-
カスタムハンドラーには、
WEB-INF/jboss-web.xmlファイルを使用してパラメーターを設定することもできます。
<jboss-web>
<http-handler>
<class-name>org.jboss.example.MyHttpHandler</class-name>
<param>
<param-name>myParam</param-name>
<param-value>foobar</param-value>
</param>
</http-handler>
</jboss-web>
これらのパラメーターが機能するには、ハンドラークラスに対応するセッターが必要です。
package org.jboss.example;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
public class MyHttpHandler implements HttpHandler {
private HttpHandler next;
private String myParam;
public MyHttpHandler(HttpHandler next) {
this.next = next;
}
public void setMyParam(String myParam) {
this.myParam = myParam;
}
public void handleRequest(HttpServerExchange exchange) throws Exception {
// do something, use myParam
next.handleRequest(exchange);
}
}
ハンドラーの定義に
WEB-INF/jboss-web.xmlを使用する代わりに、ハンドラーはWEB-INF/undertow-handlers.confファイルで定義することもできます。myHttpHandler(myParam='foobar')WEB-INF/undertow-handlers.confで定義されたハンドラーが機能するには、以下の 2 つのものを作成する必要があります。HandlerWrapperにラップされたHandlerBuilder(undertow-handlers.conf向けの対応する構文を定義し、HttpHandlerを作成します)。package org.jboss.example; import io.undertow.server.HandlerWrapper; import io.undertow.server.HttpHandler; import io.undertow.server.handlers.builder.HandlerBuilder; import java.util.Collections; import java.util.Map; import java.util.Set; public class MyHandlerBuilder implements HandlerBuilder { public String name() { return "myHttpHandler"; } public Map<String, Class<?>> parameters() { return Collections.<String, Class<?>>singletonMap("myParam", String.class); } public Set<String> requiredParameters() { return Collections.emptySet(); } public String defaultParameter() { return null; } public HandlerWrapper build(final Map<String, Object> config) { return new HandlerWrapper() { public HttpHandler wrap(HttpHandler handler) { MyHttpHandler result = new MyHttpHandler(handler); result.setMyParam((String) config.get("myParam")); return result; } }; } }ファイル
META-INF/services/io.undertow.server.handlers.builder.HandlerBuilder内のエントリー。このファイルは、たとえばWEB-INF/classesのクラスパス上にある必要があります。org.jboss.example.MyHandlerBuilder