Undertowで書いたリバースプロキシで、リモートサーバーからのレスポンスヘッダーを読む
なぜこの記事を書いた?
3日くらいハマって絶望の淵に立ったから。 とにかく情報がない。と思いきや最終的には数年前のメーリスでさがしてたものが見つかるから、実は自分の検索能力が足りてないだけの気もする。
結論: HttpServerExchange.addResponseCommitListener
を使おう
使おう。 ここで課題解決した人はお帰りください。
以下経緯とか。
リバースプロキシ?
Undertowにはリバースプロキシ機能があって、それはProxyHandlerってクラスで提供される。 HandlerってのはUndertowにおけるリクエストをさばく業務ロジックを書く場所。 ProxyHandlerは業務ロジックとしてリバースプロキシを提供する。
ProxyHandlerはProxyClientという接続先サーバーとのコネクションを確保するクラスを受け取る。こいつが自前実装可能な拡張ポイントで、必要なら自分で書くことができる。
レスポンスヘッダーを読む?
UndertowのHandlerは
class XxxHandler implements HttpHandler { @Override public void handleRequest(HttpServerExchange exchange) { // ... } }
みたいな形をしてて、こいつに別のHandlerを渡すとHandlerのチェインを実装できる。たとえば以下のように。
class XxxHandler implements HttpHandler { private HttpHandler next; public XxxHandler(HttpHandler next) { this.next = next; } @Override public void handleRequest(HttpServerExchange exchange) { // ... next.handleRequest(exchange); // <- これによって次のハンドラを呼ぶ } }
で、こう書くと普通、 next.handleRequest
の後に書いたロジックは次のハンドラーの処理終了後の HttpRequest / Response の状態を受け取って行えるという使い方を想像できると思う。
たしかにどちらも普通のHandlerならそれでいける。
でもProxyHandlerはダメ。理由は謎。
ProxyHandlerの中身を読むに exchange.dispatch
って関数を読んでて、こいつは今の処理をワーカースレッドに譲渡する関数なんだけど、普通のHandlerを実装してみても普通にレスポンスヘッダーを読み書きできてしまう。
そこで ResponseCommitListener
ですよ
[undertow-dev] Rewrite response headers in ProxyHandler
いやー、そりゃみんな同じこと考えるよね。 まじでありがとう過去のコミュニティ参加者の人。
コード
一応以下。
examples/MutlipleHandlers.java at master · blackawa/examples · GitHub