網關-基於SpringCloud Gateway的擴展開發_v0.0.1

版本號 作者 qq SpringCloud Gateway版本號 備註
v0.0.1 若布與宮合 8416837 2.1.0.RELEASE 反向代理 負載均衡 服務發現 監控埋點

原創文章轉載請註明出處 https://blog.csdn.net/cc007cc009/article/details/92570640

用途

  • 安全
  • 微服務代理
  • 監控/埋點
  • 限流
  • 路徑重寫

技術棧

  • 動態路由
  • 熔斷器
  • 服務模式

過濾器

簡介

  • 過濾器種類
    內置
    自定義
  • Filter責任鏈
    過濾器責任鏈,管理過濾器執行順序。
  • 過濾器工作原理
    在這裏插入圖片描述
    過濾器可以在發送代理請求之前或之後執行.

內置的系統過濾器

  • PrefixPath
  • StripPrefix
    springBoot yaml配置文件:
	routes:
      	- id: routetest1
        uri: https://www.baidu.com # 上游
        predicates:
        - Path=/service/baidu/s # 轉發正確. 路由路徑
        filters:
        - StripPrefix=2

路由定位器

  • Demo
    關鍵配置
spring:
  cloud:
    gateway:
      discovery:
      # 網關發現服務開啓
        locator:
        # 默認關閉
          enabled: true
          # 默認關閉
          lower-case-service-id: true

微服務API地址http://localhost:8002/system/sysDept/list
經網關代理後的地址:http://localhost:9999/service-name/system/sysDept/list,service-name是服務註冊名稱。這時在網關添加過濾器,即可攔截請求了。
注意:通過服務名訪問,不要定義路由特指。
通過網關訪問成功:
在這裏插入圖片描述
注:localhost:9999爲本地網關url。

  • 負載均衡
    通過網關訪問微服務時,默認負載均衡。
    過濾器
@Slf4j
public class RequestTimeFilter implements GatewayFilter, Ordered {
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                    if (startTime != null) {
                        log.debug("{}=={},{}=={}",
                                "請求路徑", exchange.getRequest().getURI().getRawPath(),
                                "消耗時間 ", (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );
    }

    @Override
    public int getOrder() { // 亦可註解
    // order值與優先級成反比
        return 0;
    }
}

啓動訪問,過濾器沒起效,這是因爲還需要將該過濾器加入責任鏈。見下文

	@Bean
    public RouteLocator myRoutes(RouteLocatorBuilder builder) {
        // 通過訪問.../cecjx跳轉到cecjx.com/cecjx cecjx路徑會轉交過去 PATH將作爲遠程應用的path
        return builder.routes()
                .route(p -> p
                        .path("/**/**")
                        .filters(f -> f.filter(new RequestTimeFilter()))
                        .uri("http://localhost:8002")
                        .order(0)// 起效了
                        .id("customer_filter_router")
                )
                .build();// 熔斷測試要去掉contextPath
    }

這樣就起效了。

14:56:09 [reactor-http-nio-3] DEBUG c.j.gateway.filter.RequestTimeFilter - 請求路徑==/system/sysDept/list,消耗時間 ==17ms
14:56:19 [reactor-http-nio-3] DEBUG c.j.gateway.filter.RequestTimeFilter - 請求路徑==/system/sysDept/list3,消耗時間 ==15ms
  • 全局過濾器
// 全局過濾器 優先執行
@Component
@Slf4j
public class TokenFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            log.debug("token 爲空,無法進行訪問.");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

不傳Token,無法訪問
在這裏插入圖片描述

15:49:37 [reactor-http-nio-2] DEBUG com.jxbd.gateway.filter.TokenFilter - token 爲空,無法進行訪問.

傳Token,訪問成功.Token應加密到Https請求頭.
在這裏插入圖片描述

自帶管理接口

# 配置
management:
  endpoints:
    web:
      exposure:
        include: "*"

訪問http://localhost:9999/actuator/gateway/routes
在這裏插入圖片描述
不過這裏我們不打算用自帶的Restful接口,一來官方文檔也沒說新增網關參數怎麼傳,再者我們也不希望在網關暴露這些接口,第三路由信息也需要持久化起來.參照org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint,我們自己編程來動態改變網關。

跨域

熔斷器

在路由配置熔斷器

					.route(p -> p
                        .host("*.hystrix.com")
                        .filters(f -> f
                                .hystrix(config -> config
                                .setName("mycmd")
                                .setFallbackUri("forward:/fallback")))
                        .uri("http://httpbin3.org"))
curl --dump-header - --header Host:www.hystrix.com http://localhost:9999/any # 因上游地址訪問不通,觸發熔斷

因爲訪問不到http://httpbin3.org/any,所以會觸發熔斷。

重試

限流

異常處理

* Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.http.codec.ServerCodecConfigurer' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

解決方法:
去除spring-web依賴

Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.

路由

路由種類:
路徑
參數
主機
請求頭
範圍路由
我們主要使用路徑路由,其實是做了個路徑的反向代理。
將路徑路由轉發到上游服務器,與上游服務器的url拼接起來。

動態路由

  • 是網關的核心功能之一,在不重啓網關的情況下,即可更新路由和路由權限。
代碼解釋
RouteDefinitionLocator
public interface RouteDefinitionLocator { // 實現該接口:實時獲取路由.不好用,因爲調用時讀取全部路由太耗資源了.
    Flux<RouteDefinition> getRouteDefinitions(); // 不過調用時,並不是每次都走這個方法.
}

同時也要考慮網關集羣時,路由亦需要使用中心化的存儲器存儲起來:redis、etcd、postgresql

RouteDefinitionWriter
public interface RouteDefinitionWriter { // 開發者實現該接口
    Mono<Void> save(Mono<RouteDefinition> route); // 保存單個路由,只是將路由存入客戶自定義的數據庫.

    Mono<Void> delete(Mono<String> routeId); // 刪除單個路由
}
RouteDefinitionRepository
public interface RouteDefinitionRepository extends RouteDefinitionLocator, RouteDefinitionWriter {
} // 繼承上述兩個接口
ApplicationEventPublisherAware
public interface ApplicationEventPublisherAware extends Aware {
    void setApplicationEventPublisher(ApplicationEventPublisher var1); // 監聽
}
public interface Aware {
} // 空的
ApplicationEventPublisher
@FunctionalInterface
public interface ApplicationEventPublisher { // 事件監聽 監聽路由改變
    default void publishEvent(ApplicationEvent event) { // ApplicationEvent 它的超類是EventObject
        this.publishEvent((Object)event);
    }

    void publishEvent(Object var1);
}
RouteDefinition

按這個數據結構定義路由,並存儲待使用。

@Validated
public class RouteDefinition {
	@NotEmpty
	private String id = UUID.randomUUID().toString(); // 默認uuid,一般會覆蓋這個id,以便於後續操作.

	@NotEmpty
	@Valid
	private List<PredicateDefinition> predicates = new ArrayList<>();

	@Valid
	private List<FilterDefinition> filters = new ArrayList<>();

	@NotNull
	private URI uri;

	private int order = 0;
// ... 片段 ...
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章