Spring Cloud Gateway は、Spring Cloud の新しいプロジェクトです.このプロジェクトは、Spring 5.0、Spring Boot 2.0、Project Reactor などのリアクティブ プログラミングとイベント フロー技術に基づいて開発されたゲートウェイであり、マイクロサービス アーキテクチャにシンプルで効果的な統合を提供することを目的としています. . API ルーティング管理方法。
ゲートウェイが必要な理由
ゲートウェイはサービスのゲートキーパーであり、すべてのマイクロサービスの統合されたエントリです.
ゲートウェイのコア機能特性:
- リクエスト ルーティング
- アクセス制御
- 制限する
アーキテクチャ図:
権限制御: ゲートウェイは、マイクロサービスへの入り口として、ユーザーが要求する資格があるかどうかを確認する必要があり、そうでない場合は傍受します。
ルーティングと負荷分散: すべてのリクエストは最初にゲートウェイを通過する必要がありますが、ゲートウェイはビジネスを処理しませんが、特定のルールに従ってマイクロサービスにリクエストを転送します. このプロセスはルーティングと呼ばれます. もちろん、ルーティング対象のサービスが複数ある場合は、負荷分散も必要です。
現在の制限: 要求トラフィックが高すぎる場合、ゲートウェイは、ダウンストリーム マイクロサービスが受け入れることができる速度に従って要求を解放し、過剰なサービス プレッシャーを回避します。
SpringCloud には 2 つのタイプのゲートウェイ実装があります。
gateway
zuul
Zuul はサーブレット ベースの実装であり、ブロッキング プログラミングに属します。SpringCloudGateway は、Spring5 で提供される WebFlux に基づいています。これは、リアクティブ プログラミングの実装に属し、パフォーマンスが向上しています。
ゲートウェイのクイック スタート
次に、ゲートウェイの基本的なルーティング機能について説明します。基本的な手順は次のとおりです。
- SpringBoot プロジェクト ゲートウェイの作成、ゲートウェイの依存関係を導入する
- スタートアップ クラスを作成する
- 基本的な構成とルーティング ルールを作成する
- テスト用のゲートウェイ サービスを開始する
ゲートウェイ サービスを作成し、依存関係を導入する
サービスを作成します。
依存関係のインポート:
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
スタートアップ クラスを作成する
package cn.itcast.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
基本的な構成とルーティング ルールを作成する
次の内容で application.yml ファイルを作成します。
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
パラメータPath
で指定されたアドレスに、ルールを満たすすべてのリクエストをプロキシします。uri
この例では、 で/user/**
始まるlb://userservice
。lb は負荷分散であり、負荷分散を実現するためにサービス名に従ってサービス リストをプルします。
テストを再開する
ゲートウェイを再起動します。http://localhost:10010/user/1 にアクセスすると、/user/**
ルールが満たされ、要求が uri: http://userservice/user/1 に転送され、結果が取得されます。
ゲートウェイ ルーティングのフローチャート
訪問プロセス全体は次のとおりです。
要約:
ゲートウェイの構築手順:
-
プロジェクトを作成し、nacos サービスの検出とゲートウェイの依存関係を導入します
-
基本的なサービス情報、nacos アドレス、ルーティングなど、application.yml を構成します。
ルーティング構成には次が含まれます。
-
ルート ID: ルートの一意の識別子
-
ルーティング ターゲット (uri): ルートのターゲット アドレス。http は固定アドレスを表し、lb はサービス名に基づく負荷分散を表します。
-
ルーティングアサーション (述語): ルーティングを判断するためのルール、
-
ルーティング フィルター (フィルター): 要求または応答の処理
次に、ルート アサーションとルート フィルターの詳細について説明します。
アサーション ファクトリ
設定ファイルに書くアサーションルールは単なる文字列であり、Predicate Factory に読み込まれて処理され、ルーティング判定の条件となります。
たとえば、Path=/user/** はパスに応じて一致します. このルールは次のように定義されています.
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
クラスを処理する必要があるため、SpringCloudGateway には次のような 12 を超えるアサーション ファクトリがあります。
名前 | 例証する | 例 |
---|---|---|
後 | ある時点以降のリクエストです | - After=2037-01-20T17:42:47.789-07:00[アメリカ/デンバー] |
前 | ある時点より前のリクエストです | - Before=2031-04-13T15:14:47.433+08:00[アジア/上海] |
間 | ある時点より前のリクエストです | - Between=2037-01-20T17:42:47.789-07:00[アメリカ/デンバー], 2037-01-21T17:42:47.789-07:00[アメリカ/デンバー] |
クッキー | リクエストには特定の Cookie が含まれている必要があります | - クッキー=チョコレート、ch.p |
ヘッダ | リクエストには特定のヘッダーが含まれている必要があります | - Header=X-Request-Id, \d+ |
ホスト | リクエストは、特定のホスト (ドメイン名) へのアクセスである必要があります | - ホスト = .somehost.org、 .anotherhost.org |
方法 | リクエスト メソッドは、指定されたメソッドである必要があります | - メソッド=GET、POST |
道 | リクエストパスは、指定されたルールに準拠する必要があります | - Path=/red/{segment},/blue/** |
クエリ | リクエスト パラメータには、指定されたパラメータが含まれている必要があります | - クエリ=名前、ジャックまたは - クエリ=名前 |
リモートアドレス | リクエスタの IP は指定された範囲内にある必要があります | - RemoteAddr=192.168.1.1/24 |
重さ | ウェイトハンドリング |
フィルター工場
GatewayFilter はゲートウェイで提供されるフィルターであり、ゲートウェイに入る要求とマイクロサービスから返される応答を処理できます。
ルート フィルターの種類
Spring は、31 の異なるルート フィルター ファクトリを提供します。例えば:
名前 | 例証する |
---|---|
AddRequestHeader | 現在のリクエストにリクエスト ヘッダーを追加する |
リクエストヘッダーの削除 | リクエストからリクエスト ヘッダーを削除する |
AddResponseHeader | 応答結果に応答ヘッダーを追加する |
応答ヘッダーの削除 | 応答結果から応答ヘッダーを削除します |
RequestRateLimiter | リクエストされたトラフィックを制限する |
リクエスト ヘッダー フィルタ
AddRequestHeader を例に説明しましょう。
要件: userservice へのすべてのリクエストにリクエスト ヘッダーを追加します。Truth=itcast は最高です!
ゲートウェイ サービスの application.yml ファイルを変更して、ルート フィルタリングを追加するだけです。
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
現在のフィルターは userservice ルートの下に記述されているため、userservice へのアクセス要求に対してのみ有効です。
デフォルトのフィルター
すべてのルートに対して有効にしたい場合は、デフォルトでフィルター ファクトリを記述できます。形式は次のとおりです。
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, Itcast is freaking awesome!
要約する
フィルターは何をしますか?
-
リクエスト ヘッダーの追加など、ルーティングされたリクエストまたはレスポンスを処理する
-
ルートの下に構成されたフィルタは、現在のルートのリクエストに対してのみ有効です
defaultFilters の役割は何ですか?
- すべてのルートに適用されるフィルター
グローバル フィルタ
前述のフィルターの場合、ゲートウェイは 31 種類を提供しますが、各フィルターの役割は固定されています。リクエストをインターセプトして独自のビジネス ロジックを実行したい場合、それを実現する方法はありません。
グローバル フィルター アクション
グローバル フィルターの役割は、GatewayFilter と同様に、ゲートウェイに入るすべての要求とマイクロサービス応答を処理することです。違いは、GatewayFilter は構成によって定義され、処理ロジックが固定されているのに対し、GlobalFilter のロジックは独自のコードを記述して実装する必要があることです。
これは、GlobalFilter インターフェイスを実装することによって定義されます。
public interface GlobalFilter {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回标示当前过滤器业务结束
*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
フィルターにカスタム ロジックを記述して、次の機能を実現します。
- ログイン状態判定
- 許可チェック
- 現在の制限などを要求します。
カスタム グローバル フィルタ
要件: グローバル フィルターを定義し、要求を傍受し、要求のパラメーターが次の条件を満たしているかどうかを判断します。
-
パラメータに権限があるかどうか、
-
認証パラメーターの値が admin かどうか
両方が満たされている場合はリリース、そうでない場合はインターセプト
達成:
ゲートウェイでフィルターを定義します。
package cn.itcast.gateway.filters;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
// 2.获取authorization参数
String auth = params.getFirst("authorization");
// 3.校验
if ("admin".equals(auth)) {
// 放行
return chain.filter(exchange);
}
// 4.拦截
// 4.1.禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 4.2.结束处理
return exchange.getResponse().setComplete();
}
}
フィルタの実行順序
ゲートウェイに入るリクエストは、現在のルート フィルター、DefaultFilter、GlobalFilter の 3 種類のフィルターに遭遇します。
ルートを要求した後、現在のルート フィルター、DefaultFilter、および GlobalFilter がフィルター チェーン (コレクション) に結合され、並べ替え後に各フィルターが順番に実行されます。
並べ替えのルールは何ですか?
- 各フィルタは int 型の順序値を指定する必要があります。順序値が小さいほど、優先度が高くなり、実行順序が高くなります。
- GlobalFilter は Ordered インターフェースを実装するか、自分で指定した @Order アノテーションを追加して、注文値を指定します。
- ルートフィルターとdefaultFiltersの順番はSpringで規定されており、デフォルトでは宣言順に1から増加する。
- フィルターの順序値が同じ場合、defaultFilter > Route Filter > GlobalFilter の順序で実行されます。
詳細については、ソース コードを表示できます。
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()
その方法は、最初に defaultFilters をロードし、次にルートのフィルターをロードしてからマージすることです。
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()
このメソッドは、グローバル フィルターを読み込み、それを前のフィルターとマージし、順序に従って並べ替え、フィルター チェーンを編成します。
クロスドメインの問題
クロスドメイン問題とは
クロスドメイン: 以下を含む、一貫性のないドメイン名はクロスドメインです。
-
異なるドメイン名: www.taobao.com と www.taobao.org と www.jd.com と miaosha.jd.com
-
同じドメイン名、異なるポート: localhost:8080 と localhost:8081
クロスドメインの問題: ブラウザは、リクエストの発信者がサーバーに対してクロスドメインの ajax リクエストを行うことを禁止し、リクエストはブラウザによってインターセプトされます
解決策: CORS、これは事前に学習しておく必要があるため、ここでは繰り返しません。
知らない人はhttps://www.ruanyifeng.com/blog/2016/04/cors.html
クロスドメインの問題をシミュレートする
クロスドメイン問題のあるWebページをTomcatやnginxなどのWebサーバーに入れ、起動してアクセスします。
ブラウザ コンソールに次のエラーが表示されます。
localhost:8090 から localhost:10010 にアクセスします。ポートが異なります。明らかにクロスドメイン リクエストです。
クロスドメインの問題を解決する
ゲートウェイ サービスの application.yml ファイルに、次の構成を追加します。
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期