API のリバースプロキシである Spring Cloud Gateway ですが、ドキュメントに書いてない謎も多い産物で、頭を痛めています。今回はその中から2つほど取り上げます。
Filter の有効化
Spring Cloud Gateway において、filter を有効化するには、以下の準備が必要になります。
- @Component をつけてコンポーネントとしてフィルタを定義する。
- GlobalFilter を実装する。または AbstractGatewayFilterFactory を拡張する。名称を MyFilterGatewayFilterFactory とします。
- GatewayFilter apply(Config config) を実装する。
- @RestController として MyRouteLocator を定義する。
- MyRouteLocator 中、@Bean として RouteLocator myRoutes(RouteLocatorBuilder builder) を実装する。
ここまではよいのですが、どのフィルタを働かせるかは application.yaml に記述します。(当初は気づかなかった。)
- 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 の実装としてはわざとレスポンスボディを見えなくしているとしか思えないのですが、それがどういう意図のものに実装されているのか今一つ見えません。
コメントを残す