Gateway は、全てのマイクロサービスの統一エントリポイントで、以下の機能があるよ。
- 認証と認可のチェック: ゲートウェイはマイクロサービスのエントリポイントとして、ユーザーがリクエストの資格を持っているか確認する必要があるんだ。もしなければ、インターセプトするよ。
- リクエストルーティング、ロードバランシング: 全てのリクエストはGatewayを通過する必要があるんだけど、ゲートウェイはビジネスロジックを処理しないんだ。代わりに、特定のルールに基づいてリクエストを特定のマイクロサービスに転送するよ。このプロセスをルーティングって呼ぶんだ。もちろん、ルーティング先のサービスが複数ある場合は、ロードバランシングも必要になるね。
- リクエストレートリミット: リクエストトラフィックが高すぎる場合、ゲートウェイでダウンストリームのマイクロサービスが受け入れられる速度に合わせてリクエストを許可し、サービスの負荷が過大になるのを防ぐよ。
SpringCloud のゲートウェイ実装は2種類あるんだ。
- Zuul: Servlet ベースの実装で、ブロッキングプログラミングに属するよ。
- SpringCloudGateway: Spring5 で提供される WebFlux ベースで、リアクティブプログラミングの実装に属し、より良いパフォーマンスを持ってるんだ。
簡単入門
プロジェクトを作って、依存関係を追加しよう。
| |
基本設定とルーティングルールを書こう。
| |
そしたら <localhost:10010/user/1> にアクセスしてテストしてみてね。
ルーティング設定には、以下が含まれるよ。
- ルーティングID: ルーティングの一意な識別子
- ルーティングターゲット (uri): ルーティングのターゲットアドレス。
httpは固定アドレスを、lbはサービス名に基づくロードバランシングを表すよ。 - ルーティングアサーション (predicates): ルーティングのルールを判断するもので、合致すればルーティング先に転送されるよ。
- ルーティングフィルター (filters): リクエストやレスポンスを処理するよ。
アサーションファクトリ
設定ファイルに書いたアサーションルールはただの文字列で、これらの文字列は Predicate Factory によって読み込まれて処理され、ルーティング判断の条件に変換されるんだ。
例えば、上記の例の Path=/user/** はパスによるマッチングで、このルールは org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory クラスで処理されるよ。似たようなアサーションファクトリにはこんなのがあるんだ。
| 名前 | 説明 | 例 |
|---|---|---|
| After | 特定の時刻以降のリクエスト | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
| Before | 特定の時刻以前のリクエスト | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
| Between | 2つの時刻の間のリクエスト | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
| Cookie | 特定のクッキーを含むリクエスト | - Cookie=chocolate, ch.p |
| Header | 特定のヘッダーを含むリクエスト | - Header=X-Request-Id, \d+ |
| Host | 特定のホスト(ドメイン)へのリクエスト | - Host=.somehost.org,.anotherhost.org |
| Method | 指定されたリクエストメソッド | - Method=GET,POST |
| Path | 指定されたルールに合致するリクエストパス | - Path=/red/{segment},/blue/** |
| Query | 指定されたパラメータを含むリクエスト | - Query=name, Jackまたは- Query=name |
| RemoteAddr | 指定された範囲内のリクエスト元IP | - RemoteAddr=192.168.1.1/24 |
| Weight | 重み付け処理 |
フィルターファクトリ
GatewayFilter は、ゲートウェイで提供される一種のフィルターで、ゲートウェイに入ってくるリクエストやマイクロサービスから返されるレスポンスを処理できるよ。
Spring は31種類の異なるルートフィルターファクトリを提供しているんだ。例えばこんな感じ。
| 名前 | 説明 |
|---|---|
| AddRequestHeader | 現在のリクエストにリクエストヘッダーを追加する |
| RemoveRequestHeader | リクエストからリクエストヘッダーを削除する |
| AddResponseHeader | レスポンス結果にレスポンスヘッダーを追加する |
| RemoveResponseHeader | レスポンス結果からレスポンスヘッダーを削除する |
| RequestRateLimiter | リクエストのトラフィックを制限する |
詳しい情報はここを参考にしてね: https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/gatewayfilter-factories.html
リクエストヘッダーフィルター
リクエストヘッダーフィルターを例にとると、userService に入る全てのリクエストに ‘Hello=World’ というリクエストヘッダーを追加するよ。
gateway の application.yml を修正して、ルーティングフィルターを追加するんだ。
| |
そしたら Controller を修正してテストできるよ。
| |
デフォルトフィルター
もし全てのルートに効果を適用したいなら、フィルターファクトリを default の下に書けばいいよ。
| |
グローバルフィルター
ゲートウェイには31種類のフィルターが提供されているけど、それぞれのフィルターの役割は固定されてるんだ。もしリクエストをインターセプトして、独自のビジネスロジックを実装したい場合は、そのままじゃ実現できないんだよね。
一方、グローバルフィルターもゲートウェイに入る全てのリクエストとマイクロサービスのレスポンスを処理する役割があって、GatewayFilter と同じだよ。違いは、GatewayFilter が設定を通じて定義され、処理ロジックが固定されているのに対して、GlobalFilter のロジックは自分でコードを書いて実装する必要があるってこと。GlobalFilter インターフェースを実装することで定義するんだ。
| |
filter でカスタムロジックを書くことで、以下の機能を実装できるよ。
- ログイン状態の判断
- 権限のチェック
- リクエストレートリミットなど
簡単な使い方
目標:グローバルフィルターを定義して、リクエストをインターセプトし、リクエストのパラメータが以下の条件を満たしているか判断するよ。
- パラメータに
authorizationが含まれているか authorizationパラメータの値がadminであるか
もし両方満たしていれば通過させて、そうでなければインターセプトするよ。
まず gateway でフィルターを定義するよ。
| |
フィルターの実行順序
リクエストがゲートウェイに入ると、3種類のフィルターに出会うよ。現在のルートのフィルター、DefaultFilter、GlobalFilterだね。
リクエストがルーティングされた後、現在のルートフィルターと DefaultFilter、GlobalFilter は1つのフィルターチェーン(コレクション)にマージされて、ソートされた後に各フィルターが順番に実行されるんだ。
各フィルターには int 型の order 値があって、order 値が小さいほど優先度が高く、実行順序も前になるよ。
ルートフィルターと defaultFilter の order 値は Spring によって指定されて、デフォルトでは1からインクリメントされるんだ。
GlobalFilter は Ordered インターフェースを実装するか、または @Order アノテーションを追加することで order 値を指定できるよ。これは自分たちで指定するんだ。
フィルターの order 値が同じ場合、defaultFilter > ルートフィルター > GlobalFilter の順序で実行されるよ。
その中でインターフェースを実装して order 値を指定する方法はこれだね。
| |
クロスドメイン問題
同一オリジンとは、プロトコルが同じ、IPまたはドメインが同じ、ポートが同じことを指すよ。
クロスドメイン問題:ブラウザがリクエストの発信元がサーバーとクロスドメインのAjaxリクエストを発生させるのを禁止し、リクエストがブラウザによってインターセプトされる問題のこと。その解決策は CORS だよ。
| |