Jetty(組み込み)でこんな事したい時はどうするの?リスト
2017/12/28
一昨日紹介した奴を作ってる時の成果?です。
Jettyって便利なんだけど情報があんまり多くないんだよね、ましてや組み込みモードともなると。
スポンサーリンク
Jettyでアレコレしたいよ
JavaプログラムでHTTP機能を内蔵する時にJettyが超便利なのは間違いありません。
便利というか、他に選択肢ないよね。情報が少なくてもやらざるを得ない状況はあるでしょう。という訳で少しでも情報を増やそうと思ふ。
使用するのはJetty 9.4.8、Java8、Maven、良くある組み合わせですね。
とりあえず良くありそうな基本的な設定から。
ポート番号の指定
new Server();する時にポート番号を渡す。
Server server = new Server(8080);
簡単。
サーバーバージョン表示したくない
定番ですね。
forでブンブン回してひたすらsetSendServerVersionをfalseにしていく
// Server server = new Server();
for(Connector c : server.getConnectors()) {
for(ConnectionFactory f : c.getConnectionFactories()) {
if(f instanceof HttpConnectionFactory) {
((HttpConnectionFactory)f).getHttpConfiguration().setSendServerVersion(false); // <- コレ
}
}
}
ちなみにJava8のStreamでやるならflatMapを使う。
// Server server = new Server();
Stream.of(server.getConnectors())
.flatMap(c -> c.getConnectionFactories().stream())
.flatMap(f -> (f instanceof HttpConnectionFactory) ? Stream.of((HttpConnectionFactory) f) : Stream.empty())
.forEach(f -> f.getHttpConfiguration().setSendServerVersion(false)); <- コレ
まだ始まったばかりなのに既にめんどくさい
Keep-Aliveの有効/無効
デフォルト有効みたいです、「明示的に有効にする」という事は出来ないみたい。
レスポンスヘッダに「Connection: Keep-Alive」はないが、これが必要なのはHTTP/1.0で、HTTP/1.1では指定されていなくてもKeep-Aliveを有効にするのが規格的に正しい挙動。
気になるなら「curl -v http://アドレス/ http://アドレス/」ってしてみるといいよ。「Re-using existing connection!」って表示されたら接続が再利用されている(Keep-Aliveが有効になっている)
無効にするなら、後述のカスタムヘッダを応答する方法で「Connection: close」を応答すればよい。
静的ファイル配信編
あんまり居ないと思うけど、静的ファイルを配信したい場合のアレコレ。
静的ファイル配信の基本形
基本的にはResourceHandlerを作成してServerに追加する。
HandlerList handlers = new HandlerList();
ResourceHandler resource = new ResourceHandler();
resource.setResourceBase("./webroot");
handlers.addHandler(resource);
server.setHandler(handlers);
ResourceHandlerに色々設定する、WebRootであればsetResourceBaseとか(ファイルを指定するのに引数がStringって嫌だなぁ……FileかPathが良い)
ファイル一覧の表示
世界で最初にこの機能を実装した人、何を思ってわざわざこんなお節介を……?
ResourceHandler#setDirectoriesListed()を設定する。
// 一覧表示しない
resource.setDirectoriesListed(false);
// 一覧表示する
resource.setDirectoriesListed(true);
これが役に立つ時って?
index.html以外も指定したい
ResourceHandler#setWelcomeFiles()で設定する。
resource.setWelcomeFiles(new String[]{ "index.html" });
引数がString配列ってのが地味にめんどい、String可変長引数にしてくれたらよかったのに。
ところで、ResourceHandlerってどちらにせよ静的ファイルしか返せないんだからindex.html以外を指定するような事はあるんだろうか?
キャッシュさせない
ResourceHandler#setCacheControl()を使う
resource.setCacheControl("no-store");
ちなみに「キャッシュさせない」のがno-storeであって、「キャッシュしても良いけど使う前に必ず最新か確認しろ」なのがno-cache
全然意味が違うので間違えちゃダメよん
込み入った事情編
込み入った事情があるような設定
バインドアドレスを指定したい
例えば「バックエンド用なので外部から接続されないように127.0.0.1にしたい」時とかかな?
ポート番号を指定していた場所にInetSocketAddressを指定する。
こんな感じ。
new Server(new InetSocketAddress("127.0.0.1",8080));
ただ、127.0.0.1にすると127.0.0.1でしか(::1では)アクセス出来なくなる。127.0.0.1と::1の両方にバインドさせるのはどうするんだろう?
レスポンスヘッダーを弄りたい
HeaderPatternRuleを使う。HeaderPatternRuleを使う場合はjetty-rewriteが必要。
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-rewrite</artifactId>
<version>9.4.8.v20171121</version>
</dependency>
でもって、例えば全てのレスポンスに「Connection: close」を付ける場合はこう
HandlerList handlers = new HandlerList();
// RewriteHandlerを用意
RewriteHandler rewrite = new RewriteHandler();
// HeaderPatternRuleを用意
HeaderPatternRule rule = new HeaderPatternRule();
rule.setPattern("/*");
rule.setName("Connection");
rule.setValue("close");
// RewriteHandlerにHeaderPatternRuleを追加
rewrite.addRule(rule);
handlers.addHandler(rewrite);
server.setHandler(handlers);
めんどくさいぞ……?!
setPatternが正規表現なのかglobなのかは知らない。「*.js」ってするとjsにだけマッチさせられる。
ロガーを変えたい
Javaロガー界隈がカオスなのは有名な話ですね。JettyはSlf4jを使っているので、ロガーを変えたい時はブリッジが必要です。
例として、Log4j2を使う場合はMavenにブリッジ(log4j-slf4j-impl)を追加。
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.10.0</version>
</dependency>
でもって、Slf4jを使うように設定する。
try {
Log.setLog(new Slf4jLog());
// 通常は必要になった段階で初期化されるが
// 初期化を明示したい(初期化されるまで待ちたい)場合はinitialized()を呼ぶ
//Log.initialized();
} catch (Exception e) {
e.printStackTrace();
}
カオスになってきたね。
リクエストログをコンソールに出したい
Slf4jRequestLogをServer#setRequestLogにセットする。
server.setRequestLog(new Slf4jRequestLog());
厳密にはコンソールではなくSlf4jにログレベルinfoで送られているだけなので、ロガー側でコンソールに出力するように設定しておかなければならない。
めんどくさいね
Jetty、軽量かつ高機能なんだけどめんどくさいね。
今回紹介したのはほんの一例で、その気になればVirtualHostとかSSLとか、果てはHTTP/2やらWebSocketまで使えてしまう。
つまり、「めっちゃ設定めんどくさい」
とりあえず使うのはこれくらいだろうし、この記事はこれくらいで終わらせるとする。