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