Spring Cloud Gateway のエトセトラ

API のリバースプロキシである Spring Cloud Gateway ですが、ドキュメントに書いてない謎も多い産物で、頭を痛めています。今回はその中から2つほど取り上げます。

Filter の有効化

Spring Cloud Gateway において、filter を有効化するには、以下の準備が必要になります。

  1. @Component をつけてコンポーネントとしてフィルタを定義する。
  2. GlobalFilter を実装する。または AbstractGatewayFilterFactory を拡張する。名称を MyFilterGatewayFilterFactory とします。
  3. GatewayFilter apply(Config config) を実装する。
  4. @RestController として MyRouteLocator を定義する。
  5. MyRouteLocator 中、@Bean として RouteLocator myRoutes(RouteLocatorBuilder builder) を実装する。

ここまではよいのですが、どのフィルタを働かせるかは application.yaml に記述します。(当初は気づかなかった。)

  1. Application.yaml に filter を登録する。
server:
  port: 8082
  servlet:
    context-path: gw

spring:
  cloud:
    gateway:
      routes:
        - id: all
          uri: http://httpbin.org/
          predicates:
            - Path=/*
          filters:
            - name: MyFilter
  application:
    name: filter-demo

  reactor:
    context-propagation: AUTO
...

フィルタの正式クラス名は MyFilterGatewayFilterFactory ですが、YAML には MyFilter のみ記載します。(Spring Cloud Gateway のお作法)

サーバからのレスポンスの取得

ServerWebExchange インスタンスはレスポンスヘッダを取得することは可能ですが、なぜかレスポンスボディを取得することはできません。exchange.getAttributes() で調べてもレスポンスボディを与えそうなキーがないのです。

とはいえ、全く方策がないわけではなく、少し汚いやり方になりますが、MyRouteLocator の myRoutes() で以下のようにすれば取得可能です。

@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
  return builder.routes()
    .route(p -> p
      .path("/*")
      .filters(f -> f
        .modifyResponseBody(String.class, String.class, (exchange, s) -> {
          // ここで取得できる s はレスポンス String
          return Mono.just(s);
        }))
      .uri("http://httpbin.org/"))
    .build();
}

でも一旦作成したレスポンスをオンメモリに展開するとか、そもそもストリームじゃないとかごにょごにょした問題があって、最終回と言うにはほど遠い。

Spring Cloud Gateway の実装としてはわざとレスポンスボディを見えなくしているとしか思えないのですが、それがどういう意図のものに実装されているのか今一つ見えません。

投稿者について
みのしす

小さいときは科学者になろうとしたのに、その時にたまたま身に着けたプログラミングで未だに飯を食っているしがないおじさんです。(年齢的にはもうすぐおじいさん)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です