2011年06月11日

Jettyで302リダイレクトをするコードを書く

昨日はJettyを静的コンテンツを読むだけのシンプルな設定で立ち上げて、テスト用のHTTPサーバとして使ってみた。

今日はその続き。HTTPのテストをする際に出てくるのが、リダイレクト関連。5回までリダイレクトしてそれ以上になったら止まれみたいなコードをテストする際に、さらっとテストしやすいリダイレクト設定が書けるとありがたい。

リダイレクトについてはRewriteHandlerを使えばいいらしい。

通常は下記JavaDocに書いてあるようなXMLで指定するようだ。

http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/rewrite/handler/RewriteHandler.html

ForwardedSchemeHeaderRuleでhttp → httpsへの遷移をしたり、RewriteRegexRuleで正規表現付きの遷移とかも指定できたりと、いろいろと便利そう。

今回はコード上でループしながらリダイレクト設定とかを入れたいので、XMLは使わず直接ルールを書くことに。

RewriteHandlerの設定は以下のように書くらしい。
import org.eclipse.jetty.rewrite.handler.{ RewriteHandler, RewritePatternRule }
val rewriteHandler = new RewriteHandler
val rule = new RewritePatternRule
rule.setPattern("/redirect1.html")
rule.setReplacement("/redirect2.html")
rewriteHandler.addRule(rule)

尚、上記のコードを実行するにはjetty-rewriteが必要。

で、上記のHandlerをServerに追加するわけだけど、Jetty7でHandlerを複数実行する方法は3種類あるらしい。

・HandlerWrapper : ネストして複数のHandlerを実行
・HandlerCollection : すべてのHandlerを順に最後まで実行
・HandlerList : Handlerを順に実行し、handledされたら終了

この3つ。

ServerクラスはHandlerWrapperを継承している。ので、Serverのインスタンスに対してsetHandlerを実行すると、HandlerWrapperと同じ挙動になる。HandlerWrapperはDecoratorパターンっぽく、すべてのHandlerをネストして実行する。

HandlerCollectionは複数のHandlerを順序を持った上で保持する。実行時は、登録されたHandlerがすべて実行される。途中でマッチするパターンとかが実行された後も、構わず最後まで実行を続ける。

HandlerListはHandlerCollectionを継承していて、HandlerCollectionと同じように順序を持った複数のHandlerを保持する。HandlerCollectionとの違いは、handledされた時点で次のHandlerを呼び出さずに終了するところ。

そのためHandlerListはaddする順序が大事になる。たとえばHandlerListにResourceHandler、RewriteHandlerの順で設定すると、ResourceHandlerが先に呼ばれてしまい、リライトまで処理が届かなくなる。

今回のリダイレクトの場合は、リライトルールに引っかかったら即お引越ししてもらいたいので、HandlerListでRewrite、Resourceの順でHandlerを設定したら動いてくれた。

というわけで、302でリダイレクトするコードはこんな感じでいけた。
import org.eclipse.jetty.server.handler.{ ResourceHandler, HandlerList }
import org.eclipse.jetty.rewrite.handler.{ RewriteHandler, RewritePatternRule }

// ResourceHandlerの設定
val resourceHandler = new ResourceHandler
resourceHandler.setResourceBase("htdocs")

// RewriteHandlerの設定
val rewriteHandler = new RewriteHandler
val rule = new RewritePatternRule
rule.setPattern("/redirect1.html")
rule.setReplacement("/redirect2.html")
rewriteHandler.addRule(rule)

// HandlerListに追加
val handlerList = new HandlerList
handlerList.addHandler(rewriteHandler)
handlerList.addHandler(resourceHandler)

// Serverの起動
val server = new Server(8083)
server.setHandler(handlerList)
server.join

通常のhandlerパッケージの中には、MovedContextHandlerというのもいる。こちらはRewriteHandlerのような詳細なリダイレクト設定はできないけど、指定したパスから別のパスに飛ばす分には普通に実行できるようだ。
// MovedContextHandlerの設定
val movedHandler = new MovedContextHandler
movedHandler.setContextPath("/moved1.html")
movedHandler.setNewContextURL("/moved2.html")