マイクロサービス入門 ---SpringCloud (2)
1.Nacos構成管理
Nacos は登録センターであるだけでなく、構成管理にも使用できます。
1.1. 統合構成管理
デプロイされるマイクロサービスのインスタンスが増え、数十、数百に達すると、マイクロサービスの構成を 1 つずつ変更するのはストレスがかかり、エラーが発生しやすくなります。すべてのインスタンスの構成を一元管理できる、統合された構成管理ソリューションが必要です。
Nacos は、構成を一元管理できる一方で、構成の変更を即座にマイクロサービスに通知して、構成のホット アップデートを実現できます。
1.1.1. nacos に設定ファイルを追加する
nacos で構成を管理するにはどうすればよいですか?
次に、ポップアップ フォームに構成情報を入力します。
注: プロジェクトのコア構成は、nacos 管理に追加する前にホットアップデートする必要があります。めったに変更されない一部の構成は、マイクロサービスにローカルに保存した方がよいでしょう。
1.1.2. マイクロサービスから設定をプルする
マイクロサービスは、nacos で管理されている構成をプルし、ローカルの application.yml 構成とマージして、プロジェクトの起動を完了する必要があります。
しかし、application.yml が読み込まれていない場合、nacos アドレスを知るにはどうすればよいでしょうか?
したがって、Spring では新しい構成ファイル、bootstrap.yaml ファイルが導入され、application.yml の前に読み取られます。プロセスは次のとおりです。
1) nacos-config 依存関係を導入する
まず、user-service サービスに nacos-config のクライアント依存関係を導入します。
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2) bootstrap.yaml を追加します。
次に、次の内容を含む bootstrap.yaml ファイルを user-service に追加します。
spring:
application:
name: userservice # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
file-extension: yaml # 文件后缀名
ここで、nacos アドレスは spring.cloud.nacos.server-addr に基づいて取得され、さらに次のとおりに取得されます。
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
ファイルIDとして設定を読み込みます。
この場合、次のようになりますuserservice-dev.yaml
。
3) nacos 設定の読み取り
ビジネス ロジックを user-service の UserController に追加し、pattern.dateformat 構成を読み取ります。
完全なコード:
package cn.itcast.user.web;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Value("${pattern.dateformat}")
private String dateformat;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}
// ...略
}
ページにアクセスすると、次の効果がわかります。
1.2. ホットアップデートの設定
私たちの最終的な目標は、nacos の構成を変更して、再起動せずにマイクロサービスで構成を有効にできるようにすること、つまり、構成のホット アップデートです。
構成のホット アップデートを実装するには、次の 2 つの方法を使用できます。
1.2.1. 方法 1
@Value によって挿入された変数が配置されているクラスにアノテーション @RefreshScope を追加します。
1.2.2. 方法 2
@Value アノテーションの代わりに @ConfigurationProperties アノテーションを使用します。
user-service サービスで、クラスを追加し、pattern.dateformat 属性を読み取ります。
package cn.itcast.user.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}
UserController で @Value の代わりにこのクラスを使用します。
完全なコード:
package cn.itcast.user.web;
import cn.itcast.user.config.PatternProperties;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private PatternProperties patternProperties;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
}
// 略
}
1.3.設定の共有
実際、マイクロサービスが開始されると、nacos に移動して複数の構成ファイルを読み取ります。次に例を示します。
-
[spring.application.name]-[spring.profiles.active].yaml
例: userservice-dev.yaml -
[spring.application.name].yaml
、例: userservice.yaml
[spring.application.name].yaml
環境は含まれない
以下では、構成共有をテストするケースを使用します。
1) 環境共有構成を追加する
nacos に userservice.yaml ファイルを追加します。
2) ユーザーサービスで共有設定を読み取ります。
user-service サービスで、PatternProperties クラスを変更し、新しく追加されたプロパティを読み取ります。
user-service サービスで、UserController を変更し、メソッドを追加します。
3) 異なるプロファイルを使用して 2 つの UserApplication を実行します。
スタートアップ項目 UserApplication2 を変更し、そのプロファイル値を変更します。
このように、UserApplication(8081)で使用されるプロファイルはdev、UserApplication2(8082)で使用されるプロファイルはtestとなります。
UserApplication と UserApplication2 を起動します
http://localhost:8081/user/prop にアクセスすると、結果は次のようになります。
http://localhost:8082/user/prop にアクセスすると、結果は次のようになります。
開発環境とテスト環境の両方が envSharedValue 属性の値を読み取っていることがわかります。
4) 共有の優先順位を設定する
同じ属性が nacos とサービスローカルに同時に出現する場合、優先度は高と低に分けられます。
1.4. Nacos クラスターの構築
Nacosの本番環境ではクラスタ状態でデプロイする必要があり、デプロイ方法についてはプレコース資料のドキュメントを参照してください。
2.リモート通話を装う
まず、RestTemplate を使用してリモート呼び出しを開始するために使用したコードを見てみましょう。
次の問題が存在します。
•コードの可読性が低く、プログラミングの経験に一貫性がない
•複雑なパラメータを含む URL は保守が困難です
Feign は宣言型 http クライアントです。公式アドレス: https://github.com/OpenFeign/feign
その機能は、http リクエストの送信をエレガントに実装し、上記の問題を解決するのに役立ちます。
2.1.Feign が RestTemplate を置き換える
Fegin を使用する手順は次のとおりです。
1) 依存関係を導入する
order-service サービスの pom ファイルに偽の依存関係を導入します。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2) 注釈を追加する
order-service のスタートアップ クラスにアノテーションを追加して、Feign の機能を有効にします。
3) 書き込み偽クライアント
次の内容を含む新しいインターフェイスを order-service に作成します。
package cn.itcast.order.client;
import cn.itcast.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
このクライアントは主に SpringMVC アノテーションに基づいて、次のようなリモート呼び出し情報を宣言します。
- サービス名: ユーザーサービス
- リクエストメソッド:GET
- リクエストパス:/user/{id}
- リクエストパラメータ: 長い ID
- 戻り値の型: ユーザー
このように、Feign は、RestTemplate を使用せずに http リクエストを送信するのに役立ちます。
4) テスト
order-service の OrderService クラスの queryOrderById メソッドを変更し、RestTemplate の代わりに Feign クライアントを使用します。
もっとエレガントに見えませんか?
5) まとめ
Feign を使用する手順:
①依存関係を導入する
② @EnableFeignClients アノテーションを追加
③ FeignClientインターフェースを書く
④ RestTemplate の代わりに FeignClient で定義されたメソッドを使用する
2.2. カスタム構成
Feign は、次の表に示すように、多くのカスタム構成をサポートできます。
タイプ | 効果 | 説明する |
---|---|---|
偽りのロガーレベル | ログレベルの変更 | 4 つの異なるレベルが含まれます: NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 応答結果のパーサー | json 文字列を Java オブジェクトに解析するなど、http リモート呼び出しの結果を解析します。 |
feign.codec.Encoder | リクエストパラメータのエンコーディング | http リクエスト経由で簡単に送信できるようにリクエスト パラメータをエンコードする |
ふりをする。契約 | サポートされている注釈形式 | デフォルトは SpringMVC アノテーションです |
ふりをする。リトライアー | 失敗時の再試行メカニズム | 失敗したリクエストの再試行メカニズム。デフォルトはなしですが、リボンの再試行が使用されます。 |
通常の状況では、デフォルト値で十分ですが、これをカスタマイズする場合は、カスタム @Bean を作成してデフォルト Bean をオーバーライドするだけです。
以下では、例としてログを使用して、構成をカスタマイズする方法を示します。
2.2.1.設定ファイル方式
構成ファイルに基づいて偽装のログ レベルを変更すると、単一のサービスを対象にすることができます。
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
または、すべてのサービスの場合:
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
ログには 4 つのレベルがあります。
- NONE: ログ情報を記録しません。これがデフォルト値です。
- BASIC: 要求されたメソッド、URL、応答ステータス コードと実行時間のみを記録します。
- HEADERS: BASIC に基づいて、リクエストとレスポンスの追加ヘッダ情報が記録されます。
- FULL: ヘッダー情報、リクエスト本文、メタデータを含む、すべてのリクエストとレスポンスの詳細を記録します。
2.2.2.Javaコードメソッド
Java コードに基づいてログ レベルを変更することもできます。最初にクラスを宣言し、次に Logger.Level オブジェクトを宣言します。
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
これをグローバルに有効にしたい場合は、スタートアップ クラスの @EnableFeignClients アノテーションに追加します。
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
ローカルで有効になる場合は、対応する @FeignClient アノテーションに追加します。
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)
2.3.Feign の使用の最適化
Feign の最下層は http リクエストを開始し、他のフレームワークに依存します。その基礎となるクライアント実装には次のものが含まれます。
-
URLConnection: デフォルトの実装、接続プーリングをサポートしません
-
Apache HttpClient: 接続プーリングをサポート
-
OKHttp: 接続プーリングをサポートします
したがって、Feign のパフォーマンスを向上させる主な方法は、デフォルトの接続プールの代わりに接続プールを使用することですURLConnection
。
ここではデモンストレーションApache
に使用しますHttpClient
。
1) 依存関係を導入する
Apache の HttpClient 依存関係を order-service の pom ファイルに導入します。
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2) 接続プールを構成する
order-service の application.yml に設定を追加します。
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
次に、メソッド内のポイントをブレークしますFeignClientFactoryBean
。loadBalance
デバッグ モードで order-service サービスを開始します。ここにクライアントが表示されます。最下層は Apache HttpClient です。
要約、Feign の最適化:
1. 基本的なログレベルを使用してみる
2. URLConnection の代わりに HttpClient または OKHttp を使用します。
-
① feign-httpClient 依存関係を導入する
-
② 設定ファイルで httpClient 機能を有効にし、接続プールのパラメータを設定します。
2.4. ベストプラクティス
いわゆる最近の実践とは、使用中に要約された経験を指し、それを使用するのが最善の方法です。
自己研究による観察から、Feign のクライアントとサービス プロバイダーのコントローラー コードが非常に似ていることがわかります。
偽のクライアント:
UserController:
この繰り返しのコード記述を簡素化する方法はありますか?
2.4.1.継承方法
同一のコードは継承を通じて共有できます。
1) API インターフェースを定義し、定義メソッドを使用し、SpringMVC アノテーションに基づいて宣言を行います。
2) 偽クライアントとコントローラーの両方が変更されたインターフェイスを統合します
アドバンテージ:
- 単純
- コード共有を有効にしました
欠点:
-
サービスプロバイダーとサービス利用者は密接に結びついています
-
パラメータ リスト内のアノテーション マッピングは継承されないため、メソッド、パラメータ リスト、およびアノテーションをコントローラで再度宣言する必要があります。
2.4.2. 抽出方法
Feign のクライアントを独立したモジュールに抽出し、インターフェイスに関連する POJO とデフォルトの Feign 構成をこのモジュールに配置して、すべてのコンシューマーが使用できるようにします。
たとえば、UserClient、User、および Feign のデフォルト構成は feign-api パッケージに抽出され、すべてのマイクロサービスがこの依存関係パッケージを参照し、直接使用できます。
2.4.3. 抽出ベースのベストプラクティスの実装
1) 抽出
まず、feign-api という名前のモジュールを作成します。
プロジェクトの構造:
次に、feign-api に feign のスターター依存関係を導入します。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
次に、order-service に記述された UserClient、User、DefaultFeignConfiguration が feign-api プロジェクトにコピーされます。
2) order-service で feign-api を使用する
まず、order-service 内の UserClient、User、DefaultFeignConfiguration およびその他のクラスまたはインターフェイスを削除します。
feign-api の依存関係を order-service の pom ファイルに導入します。
<dependency>
<groupId>cn.itcast.demo</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>
order-service 内の上記 3 つのコンポーネントに関連するすべてのインポート パッケージを変更し、feign-api にパッケージをインポートするように変更します。
3) テストを再開します
再起動後、サービスがエラーを報告していることがわかりました。
これは、UserClient が cn.itcast.feign.clients パッケージの下にあるためです。
order-service の @EnableFeignClients アノテーションは cn.itcast.order パッケージの下にありますが、同じパッケージ内にないため、UserClient をスキャンできません。
4) スキャンパッケージの問題を解決する
方法 1:
Feign がスキャンするパッケージを指定します。
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
方法 2:
ロードする必要があるクライアント インターフェイスを指定します。
@EnableFeignClients(clients = {
UserClient.class})
3.ゲートウェイサービス ゲートウェイ
Spring Cloud Gateway は Spring Cloud の新しいプロジェクトです。このプロジェクトは、Spring 5.0、Spring Boot 2.0、Project Reactor などのリアクティブ プログラミングとイベント ストリーミング テクノロジに基づいて開発されたゲートウェイであり、マイクロサービス アーキテクチャのシンプルかつ効果的な統合を提供することを目的としています。 APIルーティング管理方式。
3.1. なぜゲートウェイが必要なのでしょうか?
ゲートウェイ ゲートウェイはサービスの門番であり、すべてのマイクロサービスへの統一された入り口です。
ゲートウェイの中核となる機能:
- リクエストルーティング
- 権限制御
- 制限する
アーキテクチャ図:
アクセス許可制御: マイクロサービスへの入り口として、ゲートウェイはユーザーがリクエストする資格があるかどうかを確認し、資格がない場合はそれをインターセプトする必要があります。
ルーティングと負荷分散: すべてのリクエストは最初にゲートウェイを通過する必要がありますが、ゲートウェイはビジネスを処理せず、特定のルールに従ってリクエストを特定のマイクロサービスに転送します。このプロセスはルーティングと呼ばれます。もちろん、ルーティング対象のサービスが複数ある場合には、負荷分散も必要になります。
電流制限: リクエスト トラフィックが多すぎる場合、ゲートウェイは過度のサービス プレッシャーを避けるために、ダウンストリーム マイクロサービスが受け入れることができる速度でリクエストを解放します。
Spring Cloud には 2 種類のゲートウェイ実装があります。
- ゲートウェイ
- ズル
Zuul はサーブレットベースの実装であり、ブロッキング プログラミングに属します。Spring Cloud Gateway は Spring 5 で提供される WebFlux をベースにしており、リアクティブ プログラミングの実装であり、パフォーマンスが向上しています。
3.2.ゲートウェイのクイックスタート
次に、ゲートウェイの基本的なルーティング機能を説明します。基本的な手順は次のとおりです。
- SpringBoot プロジェクト ゲートウェイを作成し、ゲートウェイの依存関係を導入する
- スタートアップクラスを書く
- 基本的な構成とルーティング ルールを作成する
- テスト用のゲートウェイ サービスを開始する
1) ゲートウェイ サービスを作成し、依存関係を導入する
サービスを作成します。
依存関係を導入します。
<!--网关-->
<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>
2) スタートアップクラスを書く
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);
}
}
3) 基本的な設定とルーティング ルールを作成します。
次の内容を含む 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に最初のリクエストをプロキシしlb://userservice
、サービス名に基づいてサービス リストを取得して負荷分散を実現します。
4) テストを再開します
ゲートウェイを再起動し、/user/**
ルールに準拠した http://localhost:10010/user/1 にアクセスします。リクエストは uri: http://userservice/user/1 に転送され、結果が取得されます。
5) ゲートウェイルーティングのフローチャート
訪問プロセス全体は次のとおりです。
要約:
ゲートウェイの構築手順:
-
プロジェクトを作成し、nacos サービス検出とゲートウェイの依存関係を導入する
-
基本的なサービス情報、nacos アドレス、ルーティングを含む application.yml を構成する
ルーティング設定には次のものが含まれます。
-
ルート ID: ルートの一意の識別子
-
ルーティング ターゲット (uri): ルートのターゲット アドレス。http は固定アドレスを表し、lb はサービス名に基づく負荷分散を表します。
-
ルーティング アサーション (述語): ルーティングを決定するためのルール、
-
ルーティングフィルター: リクエストまたはレスポンスを処理します。
次に、ルーティング アサーションとルーティング フィルターの詳細な知識を学習することに重点を置きます。
3.3. アサーションファクトリー
設定ファイルに記述したアサーションルールは単なる文字列であり、この文字列がPredicate Factoryに読み取られて処理され、ルーティング判定の条件となります。
たとえば、Path=/user/** はパスに従って照合されます。このルールは次で構成されます。
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
授業が来る
処理のために、SpringCloudGateway には次のようなアサーション ファクトリが十数個あります。
名前 | 説明する | 例 |
---|---|---|
後 | ある時点以降のリクエストです | - 後=2037-01-20T17:42:47.789-07:00[アメリカ/デンバー] |
前に | ある時点より前のリクエストです | - Before=2031-04-13T15:14:47.433+08:00[アジア/上海] |
間 | ある2時点より前のリクエストです。 | - 間=2037-01-20T17:42:47.789-07:00[アメリカ/デンバー]、2037-01-21T17:42:47.789-07:00[アメリカ/デンバー] |
クッキー | リクエストには特定の Cookie が含まれている必要があります | - クッキー=チョコレート、ch.p |
ヘッダ | リクエストには特定のヘッダーが含まれている必要があります | - ヘッダー=X-リクエストID、\d+ |
ホスト | リクエストは特定のホスト (ドメイン名) にアクセスするものでなければなりません | - ホスト= .somehost.org、 .anotherhost.org |
方法 | リクエストメソッドは指定されたメソッドである必要があります | - メソッド=GET,POST |
パス | リクエストパスは指定されたルールに準拠する必要があります | - パス=/red/{セグメント}、/blue/** |
クエリ | リクエストパラメータには指定されたパラメータが含まれている必要があります | - クエリ=名前、ジャック、または - クエリ=名前 |
リモートアドレス | 要求者の IP は指定された範囲内にある必要があります | - RemoteAddr=192.168.1.1/24 |
重さ | ウェイト処理 |
Path のルーティング エンジニアリングをマスターするだけで済みます。
3.4. フィルターファクトリー
GatewayFilter はゲートウェイに提供されるフィルターで、ゲートウェイに入るリクエストとマイクロサービスから返されるレスポンスを処理できます。
3.4.1. ルーティングフィルターの種類
Spring は 31 の異なるルート フィルター ファクトリを提供します。例えば:
名前 | 説明する |
---|---|
リクエストヘッダーの追加 | 現在のリクエストにリクエストヘッダーを追加します |
リクエストヘッダーの削除 | リクエストからリクエストヘッダーを削除します |
応答ヘッダーの追加 | 応答結果に応答ヘッダーを追加します。 |
レスポンスヘッダーの削除 | 応答結果から応答ヘッダーを削除します。 |
リクエストレートリミッター | 要求されたトラフィックを制限する |
3.4.2. リクエストヘッダーフィルター
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 にアクセスするリクエストに対してのみ有効です。
3.4.3.デフォルトフィルター
すべてのルートに対して有効にしたい場合は、フィルター ファクトリをデフォルトに書き込むことができます。形式は次のとおりです。
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, Itcast is freaking awesome!
3.4.4. 概要
フィルターは何をするのですか?
① リクエストヘッダーの追加など、ルーティングリクエストまたはレスポンスを処理します。
② ルーティングで設定されたフィルタは、現在のルートのリクエストにのみ有効です。
defaultFilters の役割は何ですか?
①全ルートに有効なフィルタ
3.5.グローバルフィルター
ゲートウェイには前項で学習した31種類のフィルタが用意されていますが、各フィルタの機能は固定です。リクエストをインターセプトしたい場合は、独自のビジネス ロジックを実行するだけでは実現できません。
3.5.1. グローバルフィルター機能
グローバル フィルターの役割は、ゲートウェイに入るすべてのリクエストとマイクロサービス応答を処理することであり、これは 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);
}
フィルターにカスタム ロジックを記述すると、次の機能を実現できます。
- ログイン状態の判定
- 権限の検証
- 電流制限などをリクエストします。
3.5.2. グローバルフィルターのカスタマイズ
要件: グローバル フィルターを定義し、リクエストをインターセプトし、リクエスト パラメーターが次の条件を満たしているかどうかを判断します。
-
パラメータに権限があるかどうか?
-
認可パラメータ値が 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();
}
}
3.5.3. フィルターの実行順序
ゲートウェイに入るリクエストは、現在のルート フィルター、DefaultFilter、GlobalFilter の 3 種類のフィルターに遭遇します。
ルーティングを要求した後、現在のルーティング フィルター、DefaultFilter、および GlobalFilter がフィルター チェーン (セット) にマージされ、ソート後に各フィルターが順番に実行されます。
並べ替えのルールは何ですか?
- 各フィルターは int 型の順序値を指定する必要があります。順序値が小さいほど優先順位が高く、実行順序も高くなります。
- GlobalFilter は、Ordered インターフェイスを実装するか、独自に指定する @Order アノテーションを追加することによって順序値を指定します。
- ルーティングフィルターとdefaultFilterの順序はSpringで指定されており、デフォルトは宣言順に1から増加する。
- フィルタの順序値が同じ場合、defaultFilter > ルーティングフィルタ > GlobalFilter の順で実行されます。
詳細については、ソース コードを参照してください。
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()
方法としては、まずdefaultFiltersをロードし、次に特定のルートのフィルタをロードしてマージします。
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()
このメソッドは、グローバル フィルターをロードし、前のフィルターとマージし、順序に従って並べ替えて、フィルター チェーンを編成します。
3.6. クロスドメインの問題
3.6.1. クロスドメインの問題とは何ですか?
クロスドメイン: ドメイン名が一貫していない場合、それはクロスドメインを意味し、主に次のものが含まれます。
-
異なるドメイン名: www.taabao.com、www.taabao.org、www.jd.com、miaosha.jd.com
-
ドメイン名は同じですが、ポートが異なります: localhost:8080 と localhost8081
クロスドメインの問題: ブラウザーは、リクエストの開始者とサーバー間のクロスドメイン Ajax リクエストを禁止しており、リクエストはブラウザーによってインターセプトされます。
解決策: CORS についてはすでに学習しているはずなので、ここでは詳しく説明しません。知らない友達も調べてみよう
3.6.2. クロスドメインの問題をシミュレートする
授業前の資料のページ ファイルを見つけます。
tomcatやnginxなどのWebサーバーに入れて起動し、アクセスします。
ブラウザのコンソールに次のエラーが表示されます。
localhost:8090 から localhost:10010 へのアクセスには異なるポートがあり、これは明らかにクロスドメイン要求です。
3.6.3. クロスドメインの問題の解決
ゲートウェイ サービスの 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 # 这次跨域检测的有效期