gateway基本配置教程

1、gateway簡介

路由轉發 + 執行過濾器鏈。

網關,旨在為微服務架構提供一種簡單有效的統一的API路由管理方式。同時,基於Filter鏈的方式提供瞭網關的基本功能,比如:鑒權、流量控制、熔斷、路徑重寫、黑白名單、日志監控等。
基本功能如下:

  • 統一入口:暴露出網關地址,作為請求唯一入口,隔離內部微服務,保障瞭後臺服務的安全性
  • 鑒權校驗:識別每個請求的權限,拒絕不符合要求的請求
  • 動態路由:動態的將請求路由到不同的後端集群中

2、gateway核心概念

  • 路由(Route):由一個ID,一個目標URI(最終路由到的url地址),一組斷言(匹配條件判斷)和一組過濾器定義。如果斷言為真,則路由匹配。
  • 斷言(Predicate):通過斷言匹配http請求中的任何內容(請求頭、請求參數等),如果匹配成功,則匹配斷言所在路由。
  • 過濾器(Filter):在請求前後執行業務邏輯,比如鑒權、日志監控、流量控制、修改請求頭、修改響應等。

3、路由

spring:
  cloud:
	gateway:
	  routes:
	  - id: manager						# 路由唯一標識
		uri: lb://manager_server		# 路由指向目的地URL或服務名,客戶端請求最終被轉發到的微服務
		predicates:
		- Path=/manager/** 				# 斷言:以manager開頭的請求都負載到manager_server服務
		filters:
		- RewritePath=/manager/(?<segment>.*), /$\{segment} # 過濾器:過濾掉url裡的manager,例如http://ip:port/manager/test -> http://ip:port/test
		order: 5						# 用於多個Route之間的排序,數值越小越靠前,匹配優先級越高

4、斷言

spring:
  cloud:
    gateway:
      routes:
      - id: manager
        uri: https://manager_server
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]	# 時間點後匹配
		- Before=2017-01-20T17:42:47.789-07:00[America/Denver]	# 時間點前匹配
		- Between=2017-01-20T17:42:47.789-07:00[America/Denver],2017-01-21T17:42:47.789-07:00[America/Denver]	# 時間區間匹配
		- Cookie=chocolate, ch.p						# 指定cookie正則匹配
		- Header=X-Request-Id, \d+						# 指定Header正則匹配
		- Host=**.somehost.org,**.anotherhost.org		# 請求Host匹配
		- Method=GET,POST								# 請求Method匹配指定請求方式
		- Path=/red/{segment},/blue/{segment}			# 請求路徑正則匹配
		- Query=green									# 請求包含某參數
		- Query=red, gree.								# 請求包含某參數並且參數值匹配正則表達式(匹配red;green,greet,gree...)
		- RemoteAddr=192.168.1.1/24						# 遠程地址匹配
		# 設置分組和權重,按照路由權重選擇同一個分組中的路由
      - id: preManager1
        uri: https://preManager1
        predicates:
		- Weight=group1, 2
      - id: preManager2
        uri: https://preManager2
        predicates:
		- Weight=group1, 8

5、過濾器

5.1、過濾器介紹

按生命周期分類

  • 前置(pre)過濾器: 在請求被路由之前調用:在chain.filter(exchange)前編寫過濾器邏輯
  • 後置(post)過濾器: 在路由到微服務之後調用:通過chain.filter(exchange).then(Mono.fromRunnable(() -> {過濾器邏輯})實現

按類型分類

  • 局部(GatewayFilter)過濾器:作用在某一個路由上,使用時需要關聯指定的路由
  • 全局(GlobalFilter)過濾器:作用在所有路由上,不需要在配置文件中配置

5.2、內置局部過濾器與使用

spring:
  cloud:
    gateway:
      routes:
      - id: gateway_filter
        uri: https://example.org
		predicates:
        - Path=/red/{segment}
        filters:
		# 1、為原始請求添加Header。headerName:X-Request-red,headerValue:blue。
        - AddRequestHeader=X-Request-red, blue		
		- AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green
		# 2、為原始請求添加參數。參數名,參數值
		- AddRequestParameter=red, blue
		# 3、為原始響應添加Header
		- AddResponseHeader=X-Response-Red, Blue
		# 4、剔除響應頭中重復的值
		- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
		# 5、為原始請求路徑添加前綴
		- PrefixPath=/mypath
		# 6、配置該過濾器後,會原始請求的host頭信息,並原封不動的轉發出去,而不是被gateway的http客戶端重置。
		- PreserveHostHeader
		# 7、將原始請求重定向到指定的URL,參數為http狀態碼及重定向的url
		- RedirectTo=302, https://acme.org
		# 8、移除響應Body中的指定key
		- RemoveJsonAttributesResponseBody=id,color
		# 9、移除原始請求中的指定Header
		- RemoveRequestHeader=X-Request-Foo
		# 10、移除原始請求中的指定參數
		- RemoveRequestParameter=red
		# 11、移除響應中的指定Header
		- RemoveResponseHeader=X-Response-Foo
spring:
  cloud:
    gateway:
      routes:
      - id: gateway_filter
        uri: https://example.org
		predicates:
        - Path=/red/{segment}
        filters:
		# 12、請求限流,限流算法為令牌桶,以下示例為根據用戶id做限流
		# @Configuration
		# public class RateLimiterConfig {
		#	  @Bean
		#	  public KeyResolver userKeyResolver() {
		#		  return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("userId")));
		#     }
		# }
		- name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10	# 允許用戶每秒處理的請求數
            redis-rate-limiter.burstCapacity: 20	# 令牌桶的容量,即允許在 1 秒內完成的最大請求數。設置為 0 則表示拒絕所有請求。
            key-resolver: "#{@userKeyResolver}"		# 一個引用名為 userKeyResolver 的 bean 的 SpEL 表達式
		# 13、重寫原始的請求路徑
		- RewritePath=/red/?(?<segment>.*), /$\{segment}
		# 14、重寫響應中的某個Header
		- RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***
		# 15、在轉發請求之前,強制執行websession::save操作,保存會話狀態
		- SaveSession
		# 16、修改原始的請求路徑
		- SetPath=/{segment}
		# 17、修改原始請求中的指定Header值
		- SetRequestHeader=X-Request-Red, Blue
		# 18、修改原始響應中的指定Header值
		- SetResponseHeader=X-Response-Red, Blue
		# 19、修改原始響應的響應碼
		- SetStatus=401
		# 20、剝離原始請求路徑
		- StripPrefix=2
		# 21、請求重試
		- name: Retry
          args:
            retries: 3						# 重試次數
            statuses: BAD_GATEWAY			# 應被重試的 HTTP Status Codes
            methods: GET,POST				# 應被重試的 HTTP Methods
            backoff:						# 為重試配置指數級的 backoff。重試時間間隔的計算公式為 firstBackoff * (factor ^ n),n 是重試的次數;如果設置瞭 maxBackoff,最大的 backoff 限制為 maxBackoff. 如果 basedOnPreviousValue 設置為 true, backoff 計算公式為 prevBackoff * factor.
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false
		# 22、設置允許接收最大請求包的大小。如果請求包大小超過設置的值,則返413Payload Too Large
		- name: RequestSize
          args:
            maxSize: 5000000

5.3、內置全局過濾器

  • GatewayMetricsFilter(0):統計一些網關的性能指標
  • RouteToRequestUrlFilter(10000):把瀏覽器的URL請求的Path路徑添加到路由的URI之中。
  • NettyRoutingFilter(2147483647):通過HttpClient客戶端轉發真實的URL,並存儲返回的結果。
  • NettyWriteResponseFilter(-1):在所有的其它的過濾器執行完成之後運行,將響應的數據發送給網關的客戶端。
  • ForwardRoutingFilter(2147483647):轉發路由過濾器,若URI是forward模式,過濾器會將請求轉發到DispatcherHandler來處理請求。
  • ForwardPathFilter(0):解析路徑,並將路徑轉發。
  • LoadBalancerClientFilter(10100):負載均衡,解析服務名,獲取真實服務地址。
  • RemoveCachedBodyFilter(-2147483648):清除網關上下文中的緩存的請求Body。
  • WebsocketRoutingFilter(2147483646):如果請求中的ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 屬性對應的URL前綴為 ws 或 wss,會使用Spring Web Socket 模塊轉發WebSocket請求。WebSockets可以使用路由進行負載均衡。
  • AdaptCachedBodyGlobalFilter(-2147482648):從請求中獲取body緩存到網關上下文。

5.4、自定義全局過濾器

創建自定義全局過濾器類 ,實現GlobalFilter和Ordered兩個接口。

  • GlobalFilter:全局過濾攔截器
  • Ordered:攔截器的順序,數字越低,優先級越高

5.4.1、黑名單校驗

/**
* 定義全局過濾器,會對所有路由生效
*/
@Slf4j
@Component // 讓容器掃描到,等同於註冊瞭
public class BlackListFilter implements GlobalFilter, Ordered {
	// 模擬黑名單(實際可以去數據庫或者redis中查詢)
	private static List<String> blackList = new ArrayList<>();
	static {
		blackList.add("0:0:0:0:0:0:0:1"); // 模擬本機地址
	}
	/**
	* 過濾器核心方法
	* @param exchange 封裝瞭request和response對象的上下文
	* @param chain 網關過濾器鏈(包含全局過濾器和單路由過濾器)
	* @return
	*/
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		// 思路:獲取客戶端ip,判斷是否在黑名單中,在的話就拒絕訪問,不在的話就放行
		ServerHttpRequest request = exchange.getRequest();
		ServerHttpResponse response = exchange.getResponse();
		// 從request對象中獲取客戶端ip
		String clientIp = request.getRemoteAddress().getHostString();
		// 拿著clientIp去黑名單中查詢,存在的話就決絕訪問
		if(blackList.contains(clientIp)) {
			// 拒絕訪問,返回
			response.setStatusCode(HttpStatus.UNAUTHORIZED); // 狀態碼
			log.debug("=====>IP:" + clientIp + " 在⿊名單中,將被拒絕訪問!");
			String data = "Request be denied!";
			DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
			return response.writeWith(Mono.just(wrap));
		}
		// 合法請求,放行,執行後續的過濾器
		return chain.filter(exchange);
	}
	/**
	* @return 過濾器的順序(優先級),數值越小,優先級越高
	*/
	@Override
	public int getOrder() {
		return 0;
	}
}

5.4.2、模擬登錄校驗

在過濾器中檢查請求中是否攜帶token請求頭。如果token請求頭存在則放行;如果token為空或者不存在則返回認證失敗狀態碼。

@Component
public class MyGlobalFilter implements GlobalFilter,Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        boolean token = exchange.getRequest().getHeaders().containsKey("token");
        System.out.println("----全局過濾器token----"+token);
        if (!token){
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            ServerHttpResponse response = exchange.getResponse();
            return response.setComplete();
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        return 1;
    }
}

6、一個簡單的gateway配置實例

spring:
  cloud:
    gateway:
      discovery:
        locator:
          # 表明Gateway開啟服務註冊和發現的功能,並且Spring Cloud Gateway自動根據服務發現為每一個服務創建瞭一個router,這個router將以服務名開頭的請求路徑轉發到對應的服務
          enabled: true
          # 將請求路徑上的服務名配置為小寫(因為服務註冊的時候,向註冊中心註冊時將服務名轉成大寫的瞭)
          lower-case-service-id: true
      routes:
	  # 系統管理
      - id: sys-mgt
        uri: lb://sysmgt
        predicates:
        - Path=/sys-mgt/** 	#以sys-mgt開頭的請求都負載到sysmgt服務
		- Method=GET		#隻匹配GET請求
        filters:
        - RewritePath=/sys-mgt/(?<segment>.*), /$\{segment} #過濾掉url裡的sys-mgt,例如http://ip:port/sys-mgt/test -> http://ip:port/test
		- PrefixPath=/mgt									#為請求添加/mgt前綴,再結合RewritePath過濾器,http://ip:port/sys-mgt/test -> http://ip:port/mgt/test

到此這篇關於gateway基本配置的文章就介紹到這瞭,更多相關gateway基本配置內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: