Jettyが9.3からHTTP/2に対応したので、公開から少々時間が経ってしまいましたが、実際に試してみました。...が、「とりあえず動いたけど」から先で色々手こずってしまったので、その辺りをここに覚書として残したいと思います。
Jetty自体のインストールや設定はこれまでと特に変わらないので、ここでは割愛します。また、基本的にはTLS接続を使うことになることと思われますが、これに関しては、[Java] Jetty 9 で HTTPS サーバ (SSL/TLS)等が参考になります。
とりあえずHTTP/2が動くようにしてみる
まずとにかくHTTP/2が使えるようにするには、まずhttp2
とhttp2c
の設定を追加し、JettyのALPNライブラリをインストールしてからJettyを起動します。($JETTY_HOME
と$JETTY_BASE
を分けている場合は、$JETTY_BASE
ディレクトリで作業を行います。)
$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2,http2c
$ java -jar $JETTY_HOME/start.jar --create-files
$ java -jar $JETTY_HOME/start.jar
start.d
ディレクトリを使わず、etc
ディレクトリ内のXML設定ファイルの内容を反映させたい場合は、${JETTY_HOME}/start.ini
の末尾辺りに次のような内容を追加することで対応できます。
--module=alpn,http2,http2c
etc/jetty-alpn.xml
etc/jetty-http2.xml
etc/jetty-http2c.xml
Jettyが起動したら、Chromeで接続してみると、HTTP/2でWebページを読み込んで表示するのが確認できます。なお、Jetty側が起動しているサーバ側で確認するには、リクエストログを有効にしておくと便利です。具体的には、${JETTY_HOME}/start.ini
に、
etc/jetty-requestlog.xml
を追加してからJettyを起動します。
--create-files
でエラーになる場合は (2015/9/1追記)
上記の手順のうち--create-files
の段階で、次のようなエラーが出ることがあります。
org.eclipse.jetty.start.graph.GraphException: Missing referenced dependency: alpn-impl/alpn-1.8.0_60
このエラーは、JettyのALPNモジュールと実行に用いられているJavaのバージョンに不整合がある場合に発生します。上記の例は、Java 8 SEのバージョンが1.8.0_60
で、かつ、ALPNモジュールがこのバージョンのJava向けに用意されていない場合を表しています。
この現象を解決するには、${JETTY_HOME}/modules/alpn-impl
にJavaのバージョンに対応した適切なモジュールを追加します。具体的には、Jettyのサイトから該当するモジュールをダウンロードして、前記のディレクトリに置きます。JavaのバージョンとALPNモジュールのバージョンの対応関係は、JettyのDocumentationのページに記載されています。
なお、このファイル自体はALPNモジュールのjarライブラリ本体の場所をテキストで記述しているだけですので、古いモジュールファイルをJavaのバージョンに合わせたファイル名でコピーした上で、ライブラリのURLを手動で適切なバージョンのものに書き換えることでも対処できます。
適切なバージョンのファイルが用意できれば、再びディレクトリ${JETTY_HOME}
に戻り、--create-files
の手順をやり直せば上手く行くはずです。
ところが、いくつか困ったことに...
さて、このようにして、ChromeではHTTP/2接続が確認できるものの、SafariやFirefoxなど、他のブラウザではなぜか通信が中断してしまいます。以下、こちらで確認できた解決手順を示します。
Safari 8以前など、HTTP/2非対応ブラウザへの対処
HTTP/2では、TLS接続時にプロトコルネゴシエーションを行うため際に用いられる拡張機能のApplication-Layer Protocol Negotiation (ALPN)を利用してどのプロトコルで通信するかを自動的に調整するようになっています。ところが、上記の設定だけでは、ブラウザ側がALPNに対応していない場合、TLSのセッション開始後に通信が止まってしまう、という現象が発生するようです。
これに対処するには、ALPN非対応時のデフォルトプロトコルとしてHTTP/1.1を指定するよう設定してからJettyを起動します。具体的には、start.dを用いる場合は${JETTY_HOME}/start.d/alpn.ini
を次のように修正してから(該当行のコメントを外してから)Jettyを起動します。
(前略)
## Specifies what protocol to use when negotiation fails.
jetty.alpn.defaultProtocol=http/1.1
(後略)
XML設定ファイルで設定する場合は、${JETTY_HOME}/etc/jetty-alpn.xml
を次のように修正します。
(前略)
<Set name="defaultProtocol">
<Property name="jetty.alpn.defaultProtocol" deprecated="alpn.defaultProtocol" default="http/1.1" />
</Set>
(後略)
ところで、それならばSafari 8向けにはNPN (Next Protocol Negotiation)を使ってSPDY/3.0等で通信するように誘導すれば...と考えそうになりますが、Jetty 9.3ではSPDYとNPNの対応が廃止されていますので、残念ながらHTTP/1.1にフォールバックするくらいしか方法はなさそうです。
FirefoxでHTTP/2通信ができない現象への対処
Firefox 36以降ではHTTP/2に対応しているはずですが、それでも通信できない場合があるようです。これは、JettyをOpenJDKで動作させると、一部の暗号化方式に対応していないため、Firefoxでは通信できなくなる、ということによるもののようです。
これに対処するには、OpenJDKではなく、Oracleの純正JDKを利用する必要があります。例えばCentOSのyum等、パッケージマネージャ経由では入手することができないため、OracleのJavaダウンロードサイトから直接.tar.gzアーカイブもしくはRPMパッケージを入手してインストールする必要があります。