マイクロサービス_サービス ゲートウェイ (ゲートウェイ)

目次

1. ゲートウェイが必要な理由

2. Spring Cloud Gatewayの実装

3. ゲートウェイの実践

1) ゲートウェイ サービスを作成し、依存関係を導入する

2) スタートアップクラスを書く

3) 基本的な設定とルーティング ルールを作成します。

4) テストを再開します

5) ゲートウェイルーティングのフローチャート

4. アサーションファクトリー

5. ろ過工場

1) ルーティングフィルターの種類

2) リクエストヘッダーフィルター

3) デフォルトのフィルター

4) まとめ

6. グローバルフィルタリング

1) 定義

2) ケース

3) フィルタの実行順序

7. クロスドメインの問題

1) クロスドメイン問題とは何ですか

2) クロスドメインの問題を解決する


1. ゲートウェイが必要な理由

     ゲートウェイはサービスの門番であり、すべてのマイクロサービスの統一された入り口です。一般に、異なるマイクロサービスは異なるネットワーク アドレスを持ち、外部クライアントはビジネス要件を満たすために複数のサービス インターフェイスを呼び出す必要がある場合があります。クライアントが各マイクロサービスと直接通信する場合、次の問題が発生します。

  1. クライアントは異なるマイクロサービスを複数回リクエストするため、クライアントの複雑さが増大します。
  2. クロスドメインリクエストがあり、特定のシナリオでは処理が比較的複雑になります
  3. 認証は複雑であり、サービスごとに独立した認証が必要です
  4. リファクタリングは難しく、プロジェクトが反復されると、マイクロサービスの再分割が必要になる場合があります。たとえば、複数のサービスを 1 つに結合したり、1 つのサービスを複数に分割したりできます。クライアントがマイクロサービスと直接通信する場合、リファクタリングの実装は困難になります
  5. 一部のマイクロサービスはファイアウォールやブラウザに適さないプロトコルを使用する可能性があり、直接アクセスするのは困難です

上記の問題はゲートウェイの助けを借りて解決できるため、ゲートウェイは主に次の特性を備えています。

  1. アクセス制御: マイクロサービスのエントリ ポイントとして、ゲートウェイはユーザーがリクエストに適格かどうかを確認し、適格でない場合はリクエストをインターセプトする必要があります。
  2. ルーティングと負荷分散: すべてのリクエストは最初にゲートウェイを通過する必要がありますが、ゲートウェイはビジネスを処理せず、特定のルールに従ってリクエストをマイクロサービスに転送します。このプロセスはルーティングと呼ばれます。もちろん、ルーティング対象のサービスが複数ある場合には、負荷分散も必要になります。
  3. 電流制限: リクエスト トラフィックが多すぎる場合、過度のサービス プレッシャーを避けるために、ゲートウェイはダウンストリーム マイクロサービスが受け入れることができる速度に従ってリクエストを解放します。

2. Spring Cloud Gatewayの実装

  • ゲートウェイ
  • ズル

Zuul はサーブレットベースの実装であり、ブロッキング プログラミングに属します。Spring Cloud Gateway は Spring 5 で提供される WebFlux をベースにしており、応答性の高いプログラミングの実装であり、パフォーマンスが向上しています。

3.ゲートウェイの実践

ゲートウェイを構築する基本的な手順は次のとおりです。

  1. SpringBoot プロジェクト ゲートウェイを作成し、ゲートウェイの依存関係を導入する
  1. スタートアップクラスを書く
  1. 基本的な構成とルーティング ルールを作成する
  1. テスト用のゲートウェイ サービスを開始する

1 )ゲートウェイサービスを作成し、依存関係を導入する

サービスを作成します。

依存関係をインポートします。

JavaScript
<!--网关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务発行现依赖-->
<依存関係>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2 ) スタートアップクラスを書く

TypeScript
パッケージ cn.itcast.gateway;
 
org.springframework.boot.SpringApplication をインポートします。
org.springframework.boot.autoconfigure.SpringBootApplication をインポートします。
 
@SpringBootApplication
public class GatewayApplication {     public static void main(String[] args) {         SpringApplication.run(GatewayApplication.class, args);     } }
 



3 ) 基本的な設定とルーティングルールを書く

次の内容を含む application.yml ファイルを作成します。

Bash
サーバー:
  ポート: 10010 # ゲートウェイ
ポート
スプリング:
  アプリケーション:
    名前: ゲートウェイ # サービス名
  クラウド:
    nacos:
      サーバー アドレス: localhost:8848 # nacos アドレス
    ゲートウェイ:
      ルート: # ゲートウェイ ルーティング設定
        ID: ユーザー サービス # ルート IDカスタム、一意である限り
          # uri: http://127.0.0.1:8081 # ルートのターゲット アドレス http は固定アドレスです
          uri: lb://userservice # ルートのターゲット アドレス lb はロードですバランシングの後にサービス名の
          述語が続きます: # ルーティング アサーション、つまりリクエストがルーティング ルールを満たすかどうかを判断するための条件
            - Path=/user/** # これは、次で始まる限り、パスに従って照合されます。 /user/、要件を満たしています

Path ルールに一致するすべてのリクエストは、uri パラメーターで指定されたアドレスにプロキシされます。

この例では、/user/** で始まるリクエストを lb://userservice にプロキシします。lb はロード バランシングであり、サービス名に従ってサービス リストをプルしてロード バランシングを実現します。

4 ) テストを再開します

重启网关,访问http://localhost:10010/user/1时,符合/user/**规则,请求转发到uri:http://userservice/user/1,得到了结果:

5)网关路由的流程图

整个访问的流程如下:

总结:

  1. 网关搭建步骤:
  2. 创建项目,引入nacos服务发现和gateway依赖
  3. 配置application.yml,包括服务基本信息、nacos地址、路由
  4. 路由配置包括:
  • 路由id:路由的唯一标示
  • 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
  • 路由断言(predicates):判断路由的规则,
  • 路由过滤器(filters):对请求或响应做处理

四、断言工厂

我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件例如Path=/user/**是按照路径匹配,这个规则是由

org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的,像这样的断言工厂在SpringCloudGateway还有十几个:

五、过滤工厂

 GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:

1)路由过滤器的种类

Spring提供了31种不同的路由过滤器工厂。例如:

2)请求头过滤器

下面我们以AddRequestHeader 为例来讲解。

需求:给所有进入userservice的请求添加一个请求头:Test=This is a test!

只需要修改gateway服务的application.yml文件,添加路由过滤即可:

Bash
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: lb://userservice
        predicates:
        - Path=/user/**
        filters: #
过滤器
        - AddRequestHeader=Test,This is a test! # 添加请求头

当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。

3)默认过滤器

如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:

Bash
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: lb://userservice
        predicates:
        - Path=/user/**
      default-filters: #
默认过滤项
      - AddRequestHeader=Test,This is a test! # 添加请求头   

4)总结

过滤器的作用是什么?

① 对路由的请求或响应做加工处理,比如添加请求头

② 配置在路由下的过滤器只对当前路由的请求生效

defaultFilters的作用是什么?

① 对所有路由都生效的过滤器

六、全局过滤

1)定义

上一章节讲的过滤器,网关提供了31种,但每一种过滤器的作用都是固定的。如果我们希望拦截请求,做自己的业务逻辑则没办法实现。而全局过滤器刚好可以解决这个问题,GlobalFilter的逻辑需要自己写代码实现,定义方式是实现GlobalFilter接口。

Java
public interface GlobalFilter {
    /**
     * 
处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
     *
     * @param exchange 请求上下文,里面可以获取Request、Response等信息
     * @param chain 用来把请求委托给下一个过滤器
     * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
     */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

在filter中编写自定义逻辑,可以实现下列功能:

  • 登录状态判断
  • 权限校验
  • 请求限流等

2)案例

需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

  • 参数中是否有authorization
  • authorization参数值是否为admin
  • 如果同时满足则放行,否则拦截

TypeScript
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)过滤器执行顺序

请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter,请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:

排序的规则是什么呢?

  1. 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
  2. GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
  3. 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
  4. 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

详细内容,可以查看源码:

org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法是先加载defaultFilters,然后再加载某个route的filters,然后合并。

org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链

七、跨域问题

1)什么是跨域问题

跨域:域名不一致就是跨域,主要包括:

  • 域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
  • 域名相同,端口不同:localhost:8080和localhost8081

跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题

解决方案:CORS,不知道的小伙伴可以查看https://www.ruanyifeng.com/blog/2016/04/cors.html

2)解决跨域问题

在gateway服务的application.yml文件中,添加下面的配置:

Bash
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 # 这次跨域检测的有效期

おすすめ

転載: blog.csdn.net/wanghaiping1993/article/details/129887501
おすすめ