Jetty 9.3でHTTP/2対応Webサーバを作ってみよう

  • 27
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Jetty9.3からHTTP/2に対応したので、公開から少々時間が経ってしまいましたが、実際に試してみました。...が、「とりあえず動いたけど」から先で色々手こずってしまったので、その辺りをここに覚書として残したいと思います。

Jetty自体のインストールや設定はこれまでと特に変わらないので、ここでは割愛します。また、基本的にはTLS接続を使うことになることと思われますが、これに関しては、[Java] Jetty 9 で HTTPS サーバ (SSL/TLS)等が参考になります。

とりあえずHTTP/2が動くようにしてみる

まずとにかくHTTP/2が使えるようにするには、まずhttp2http2cの設定を追加し、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の末尾辺りに次のような内容を追加することで対応できます。

${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に、

${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を起動します。

${JETTY_HOME}/start.d/alpn.ini
(前略)
## Specifies what protocol to use when negotiation fails.
jetty.alpn.defaultProtocol=http/1.1
(後略)

XML設定ファイルで設定する場合は、${JETTY_HOME}/etc/jetty-alpn.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パッケージを入手してインストールする必要があります。