2.1 環境搭建
2.1.1 引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2.1.2 編寫yml配置文件
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 網關gateway配置
gateway:
# 路由配置
routes:
- id: order_route # 路由的唯一標識,路由到order
uri: http://localhost:8020 # 需要轉發的地址
# 斷言規則,用於路由規則的匹配
predicates:
# 因為是字符串所以可以這樣寫,自動映射
# http://localhost:8088/order-serv/order/add 路由到↓
# http://localhost:8020/order-serv/order/add
- Path=/order-serv/**
# 過濾器,請求在傳遞過程中可以通過過濾器對其進行一定的修改
filters:
- StripPrefix=1 # 轉發之前去掉1層路徑(內置的一種過濾器) 變成http://localhost:8020/order/add
2.1.3 集成Nacos
引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
編寫yml配置文件
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 網關gateway配置
gateway:
# 路由配置
routes:
- id: order_route # 路由的唯一標識,路由到order
uri: lb://order-server # 需要轉發的地址 lb:使用nacos中本地的負載均衡策略 order-server 服務名
# 斷言規則,用於路由規則的匹配
predicates:
# 因為是字符串所以可以這樣寫,自動映射
# http://localhost:8088/order-serv/order/add 路由到↓
# http://localhost:8020/order-serv/order/add
- Path=/order-serv/**
# 過濾器,請求在傳遞過程中可以通過過濾器對其進行一定的修改
filters:
- StripPrefix=1 # 轉發之前去掉1層路徑(內置的一種過濾器) 變成http://localhost:8020/order/add
# 注冊到nacos中
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
discovery:
namespace: 6325e312-7f95-48d7-8d06-810047ed3956
簡寫: 去掉關於路由的配置,自動尋找服務
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 網關gateway配置
gateway:
discovery:
locator:
enabled: true # 是否啟動我們的自動識別nacos服務 可以直接用服務名作為前綴訪問,斷言也是根據服務名做斷言路由到我們的真實服務地址
# http://localhost:8088/order-server/order/add
# 注冊到nacos中
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
discovery:
namespace: 6325e312-7f95-48d7-8d06-810047ed3956
測試(這時候,就發現只要按照網關地址/微服務/接口的格式去訪問,就可以得到成功響應)

2.2 路由斷言工廠(Route Predicate Factories)配置(局部,只針對某一個路由)
作用: 當請求gateway的時候, 使用斷言對請求進行匹配, 如果匹配成功就路由轉發, 如果匹配失敗就返回404
類型:內置,自定義
2.2.1 內置斷言工廠
- 基於Datetime類型的斷言工廠
此類型的斷言根據時間做判斷,主要有三個:
AfterRoutePredicateFactory: 接收一個日期參數,判斷請求日期是否晚於指定日期
BeforeRoutePredicateFactory: 接收一個日期參數,判斷請求日期是否早於指定日期
BetweenRoutePredicateFactory: 接收兩個日期參數,判斷請求日期是否在指定時間段內
ZonedDateTime.now()
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
- 基於遠程地址的斷言工廠
RemoteAddrRoutePredicateFactory:接收一個IP地址段,判斷請求主機地址是否在地址段中
‐ RemoteAddr=192.168.1.1/24 - 基於Cookie的斷言工廠
CookieRoutePredicateFactory:接收兩個參數,cookie 名字和一個正則表達式。 判斷請求
cookie是否具有給定名稱且值與正則表達式匹配。
‐ Cookie=chocolate, ch. - 基於Header的斷言工廠
HeaderRoutePredicateFactory:接收兩個參數,標題名稱和正則表達式。 判斷請求Header是否具有給定名稱且值與正則表達式匹配。
‐ Header=X‐Request‐Id, \d+ - 基於Host的斷言工廠
HostRoutePredicateFactory:接收一個參數,主機名模式。判斷請求的Host是否滿足匹配規則。
‐ Host=**.testhost.org - 基於Method請求方法的斷言工廠
MethodRoutePredicateFactory:接收一個參數,判斷請求類型是否跟指定的類型匹配。
‐ Method=GET - 基於Path請求路徑的斷言工廠
PathRoutePredicateFactory:接收一個參數,判斷請求的URI部分是否滿足路徑規則。
‐ Path=/foo/{segment} - 基於Query請求參數的斷言工廠
QueryRoutePredicateFactory :接收兩個參數,請求param和正則表達式, 判斷請求參數是否具有給定名稱且值與正則表達式匹配。
- Query=baz, ba. - 基於路由權重的斷言工廠
WeightRoutePredicateFactory:接收一個[組名,權重], 然后對於同一個組內的路由按照權重轉發
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
2.2.2 自定義斷言工廠
1. 必須spring組件 注入bean(@Component)
2. 類必須加上RoutePredicateFactory作為結尾
3. 必須繼承AbstractRoutePredicateFactory
4. 必須聲明靜態內部類 聲明屬性來接收 配置文件中對應的斷言的信息
5. 需要結合shortcutFieldOrder進行綁定
6. 通過apply進行邏輯判斷 true就是匹配成功 false匹配失敗
注意: 命名需要以 RoutePredicateFactory 結尾,必須注入到spring中
package com.xiexie.gateway.predicate;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/**
* @Description 自定義斷言工廠
* @Date 2022-04-19 13:49
* @Author xie
*/
@Component
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {
public CheckAuthRoutePredicateFactory() {
super(CheckAuthRoutePredicateFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
// 必須跟config中的屬性名進行綁定
return Arrays.asList("name");
}
@Override
public Predicate<ServerWebExchange> apply(CheckAuthRoutePredicateFactory.Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
if (StringUtils.isEmpty(config.getName()) || !"xiexie".equals(config.getName())) {
return false;
}
return true;
}
@Override
public String toString() {
return String.format("CheckAuth: name=%s", config.getName());
}
};
}
/**
* 用於接收配置文件中 斷言的信息
*/
@Validated
public static class Config {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 網關gateway配置
gateway:
# 路由配置
routes:
- id: order_route # 路由的唯一標識,路由到order
uri: lb://order-server # 需要轉發的地址 lb:使用nacos中本地的負載均衡策略 order-server 服務名
# 斷言規則,用於路由規則的匹配
predicates:
# 因為是字符串所以可以這樣寫,自動映射
# http://localhost:8088/order-serv/order/add 路由到↓
# http://localhost:8020/order-serv/order/add
- Path=/order-serv/**
# 自定義CheckAuth斷言工廠
- CheckAuth=xiexie
# 過濾器,請求在傳遞過程中可以通過過濾器對其進行一定的修改
filters:
- StripPrefix=1 # 轉發之前去掉1層路徑(內置的一種過濾器) 變成http://localhost:8020/order/add
# 注冊到nacos中
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
discovery:
namespace: 6325e312-7f95-48d7-8d06-810047ed3956
2.3 過濾器工廠( GatewayFilter Factories)配置(局部,只針對某一個路由)
Gateway 內置了很多的過濾器工廠,我們通過一些過濾器工廠可以進行一些業務邏輯處理器,比如添加剔除響應頭,添加去除參數等

官方文檔:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
2.3.1 內置過濾器工廠
| 過濾器工廠 | 作用 | 參數 |
|---|---|---|
| AddRequestHeader | 為原始請求添加Header | Header的名稱及值 |
| AddRequestParameter | 為原始請求添加請求參數 | 參數名稱及值 |
| AddResponseHeader | 為原始響應添加Header | Header的名稱及值 |
| DedupeResponseHeader | 剔除響應頭中重復的值 | 需要去重的Header名稱及去重策略 |
| Hystrix | 為路由引入Hystrix的斷路器保護 | HystrixCommand的名稱 |
| FallbackHeaders | 為fallbackUri的請求頭中添加具體的異常信息 | Header的名稱 |
| PrefixPath | 為原始請求路徑添加前綴 | 前綴路徑 |
| PreserveHostHeader | 為請求添加一個preserveHostHeader=true 的屬性,路由過濾器會檢查該屬性以決定是否要發送原始的Host | 無 |
| RequestRateLimiter | 用於對請求限流,限流算法為令牌桶 | keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus |
| RedirectTo | 將原始請求重定向到指定的URL | http狀態碼及重定向的url |
| RemoveHopByHopHeadersFilter | 為原始請求刪除IETF組織規定的一系列Header | 默認就會啟用,可以通過配置指定僅刪除哪些Header |
| RemoveRequestHeader | 為原始請求刪除某個Header | Header名稱 |
| RemoveResponseHeader | 為原始響應刪除某個Header | Header名稱 |
| RewritePath | 重寫原始的請求路徑 | 原始路徑正則表達式以及重寫后路徑的正則表達式 |
| RewriteResponseHeader | 重寫原始響應中的某個Header | Header名稱、值的正則表達式,重寫后的值 |
| SaveSession | 在轉發請求之前,強制執行WebSession::save操作 | 無 |
| secureHeaders | 為原始響應添加一系列起安全作用的響應頭 | 無,支持修改這些安全響應頭的值 |
| SetPath | 修改原始的請求路徑 | 修改后的路徑 |
| SetResponseHeader | 修改原始響應中某個Header的值 | Header名稱,修改后的值 |
| SetStatus | 修改原始響應的狀態碼 | HTTP 狀態碼,可以是數字,也可以是字符串 |
| StripPrefix | 用於截斷原始請求的路徑 | 使用數字表示要截斷的路徑的數量 |
| Retry | 針對不同的響應進行重試 | retries、statuses、methods、series |
| RequestSize | 設置允許接收最大請求包的大 小。如果請求包大小超過設置的值,則返回 413 Payload Too Large | 請求包大小,單位為字節,默認值為5M |
| ModifyRequestBody | 在轉發請求之前修改原始請求體內容 | 修改后的請求體內容 |
| ModifyResponseBody | 修改原始響應體的內容 | 修改后的響應體內容 |
2.3.1.1 添加請求頭(上下文參考-全量配置文件)
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 網關gateway配置
gateway:
# 路由配置
routes:
- id: order_route # 路由的唯一標識,路由到order
uri: lb://order-server # 需要轉發的地址 lb:使用nacos中本地的負載均衡策略(loadbalancer) order-server 服務名
# 斷言規則,用於路由規則的匹配
predicates:
# 因為是字符串所以可以這樣寫,自動映射
# http://localhost:8088/order-serv/order/add 路由到↓
# http://localhost:8020/order-serv/order/add http://order-server/order-serv/order/add
- Path=/order-serv/**
# 自定義CheckAuth斷言工廠
- CheckAuth=xiexie # 數據放在自定義斷言工廠的config中,根據config映射到的數據值進行判斷是否匹配到
# 過濾器,請求在傳遞過程中可以通過過濾器對其進行一定的修改
filters:
- StripPrefix=1 # 轉發之前去掉1層路徑(內置的一種過濾器) 變成http://localhost:8020/order/add
# 其他的內置過濾器
- AddRequestHeader=X-Request-color, red # 添加請求頭參數
# - AddRequestParameter=color, blue # 添加請求參數
# - PrefixPath=/mall‐order # 添加前綴 對應微服務需要配置context‐path: /mall‐order
# - RedirectTo=302, https://www.baidu.com/ # 重定向到百度
# - CheckAuth=name, xiexie # 數據放在自定義的過濾器中,根據config映射到的數據進行判斷是否放行
# 注冊到nacos中
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
discovery:
namespace: 6325e312-7f95-48d7-8d06-810047ed3956
@RequestMapping("/header")
public String header(@RequestHeader("X-Request-color") String color) {
System.out.println("gateWay獲取請求頭X‐Request‐color:" + color);
return color;
}
2.3.1.2 添加請求參數(上下文參考上文全量配置文件)
- AddRequestParameter=color, blue # 添加請求參數
@RequestMapping("/parameter")
public String parameter(@RequestParam("color") String color) {
System.out.println("gateWay獲取參數color:" + color);
return color;
}
2.3.1.3 為匹配的路由統一添加前綴(上下文參考上文全量配置文件)
- PrefixPath=/mall‐order # 添加前綴 對應微服務需要配置context‐path: /mall‐order
server:
port: 8020
servlet:
context-path: /mall‐order
2.3.1.4 重定向操作(上下文參考上文全量配置文件)
- RedirectTo=302, https://www.baidu.com/ # 重定向到百度
.....
.....
還有很多,自行參照上面列表測試
2.3.2 自定義過濾器工廠
繼承AbstractNameValueGatewayFilterFactory且我們的自定義名稱必須要以GatewayFilterFactory結尾並交給spring管理。
跟自定義的斷言工廠相似
實現過濾工廠
package com.xiexie.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RedirectToGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* @Description
* @Date 2022-04-19 15:37
* @Author xie
*/
@Component
public class CheckAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> {
public CheckAuthGatewayFilterFactory() {
super(CheckAuthGatewayFilterFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("param", "value");
}
@Override
public GatewayFilter apply(CheckAuthGatewayFilterFactory.Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
Set<String> stringSet = queryParams.keySet();
if (stringSet.contains(config.getParam()) && config.getValue().equals(queryParams.get(config.getParam()).get(0))) {
// 正常請求
return chain.filter(exchange);
} else {
// 返回404並結束
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return exchange.getResponse().setComplete();
}
}
};
}
public static class Config {
private String param;
private String value;
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
配置文件中配置(上下文參考上文全量配置文件)
- CheckAuth=name, xiexie # 數據放在自定義的過濾器中,根據config映射到的數據進行判斷是否放行
2.4 全局過濾器(Global Filters)配置

局部過濾器和全局過濾器區別:
- 局部:局部針對某個路由, 需要在路由中進行配置
- 全局:針對所有路由請求, 一旦定義就會投入使用
GlobalFilter 接口和 GatewayFilter 有一樣的接口定義,只不過, GlobalFilter 會作用於所有路由
2.4.1 自定義全局過濾器
package com.xiexie.gateway.filter.global;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @Description 自定義全局過濾器
* @Date 2022-04-19 16:30
* @Author xie
*/
@Component
public class GlobalLogFilter implements GlobalFilter {
Logger log = LoggerFactory.getLogger(GlobalLogFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info(exchange.getRequest().getPath().value());
return chain.filter(exchange);
}
}
2.4.2 Reactor Netty 訪問日志(gateway自動定義的日志收集)
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#reactor-netty-access-logs
要啟用 Reactor Netty 訪問日志,請設置 -Dreactor.netty.http.server.accessLogEnabled=true
它必須是 Java 系統屬性(設置JVM環境變量的),而不是 Spring Boot 屬性。
java -jar xxxGatewat.jar -Dreactor.netty.http.server.accessLogEnabled=true
可以將日志記錄系統配置為具有單獨的訪問日志文件。(比如配置在Logback)
2.5 Gateway跨域配置(CORS Configuration)

通過yml配置的方式
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration
2.5.1 通過yml配置的方式
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 網關gateway配置
gateway:
# 跨域配置
globalcors:
cors-configurations:
'[/**]': # 允許跨域訪問的資源
allowedOrigins: "*" # 跨域允許的來源
allowedMethods: # 跨域允許的method
- GET
- POST
- DELETE
- PUT
- OPTION
2.5.1 通過java代碼方式
package com.xiexie.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* @Description 跨域配置
* @Date 2022-04-19 17:06
* @Author xie
*/
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*"); // 允許跨域的method
config.addAllowedOrigin("*"); // 允許跨域的來源
config.addAllowedHeader("*"); // 允許跨域的header頭
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config); // 允許跨域訪問的資源
return new CorsWebFilter(source);
}
}
2.6 gateway整合sentinel流控降級
網關作為內部系統外的一層屏障, 對內起到一定的保護作用, 限流便是其中之一. 網關層的限流可以簡單地針對不同路由進行限流, 也可針對業務的接口進行限流,或者根據接口的特征分組限流。
官方文檔:https://github.com/alibaba/Sentinel/wiki/網關限流

Sentinel 1.6.3 引入了網關流控控制台的支持,用戶可以直接在 Sentinel 控制台上查看 API Gateway 實時的 route 和自定義 API 分組監控,管理網關規則和 API 分組配置。
從 1.6.0 版本開始,Sentinel 提供了 Spring Cloud Gateway 的適配模塊,可以提供兩種資源維度的限流:
- route 維度:即在 Spring 配置文件中配置的路由條目,資源名為對應的 routeId
- 自定義 API 維度:用戶可以利用 Sentinel 提供的 API 來自定義一些 API 分組
Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模塊,此模塊中包含網關限流的規則和自定義 API 的實體和管理邏輯:
- GatewayFlowRule:網關限流規則,針對 API Gateway 的場景定制的限流規則,可以針對不同 route 或自定義的 API 分組進行限流,支持針對請求中的參數、Header、來源 IP 等進行定制化的限流。
- ApiDefinition:用戶自定義的 API 定義分組,可以看做是一些 URL 匹配的組合。比如我們可以定義一個 API 叫 my_api,請求 path 模式為 /foo/** 和 /baz/** 的都歸到 my_api 這個 API 分組下面。限流的時候可以針對這個自定義的 API 分組維度進行限流。
2.6.1 添加依賴
<!--gateway 整合sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.6.2 添加配置
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 整合sentinel
sentinel:
transport:
# 添加sentinel控制台
dashboard: 127.0.0.1:8858

具體操作可參考sentinel章節操作詳解
2.6.3 自定義異常
2.6.3.1 通過配置完成
server:
port: 8088
spring:
application:
name: api-gateway
cloud:
# 整合sentinel
sentinel:
transport:
# 添加sentinel控制台
dashboard: 127.0.0.1:8858
# 自定義異常
scg:
fallback:
mode: response
response-body: '{"code":"403", "msg":"限流了"}'
2.6.3.2 通過GatewayCallbackManager(代碼實現)
package com.xiexie.gateway.config;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
/**
* @Description 自定義限流異常
* @Date 2022-04-20 9:19
* @Author xie
*/
@Configuration
public class GatewaySentinelConfig {
@PostConstruct
public void init() {
BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> {
// 自定義異常處理
Map<String, String> result = new HashMap<>();
if (throwable instanceof FlowException) {
// 限流
} else if (throwable instanceof DegradeException) {
// 降級
} // .......
result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
result.put("code", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(result));
};
}
}
2.6.3 代碼實現限流降級操作
用戶可以通過 GatewayRuleManager.loadRules(rules) 手動加載網關規則 GatewayConfiguration中添加:
package com.xiexie.gateway.config;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @Description 自定義網關限流降級和異常
* @Date 2022-04-20 9:19
* @Author xie
*/
@Configuration
public class GatewaySentinelConfig {
@PostConstruct
public void init() {
// 自定義異常信息
initBlockRequestHandler();
// 自定義網關限流規則
initGatewayRules();
}
private void initBlockRequestHandler() {
BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> {
// 自定義異常處理
Map<String, String> result = new HashMap<>();
if (throwable instanceof FlowException) {
// 限流
} else if (throwable instanceof DegradeException) {
// 降級
} // .......
result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
result.put("code", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(result));
};
}
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
//resource:資源名稱,可以是網關中的 route 名稱或者用戶自定義的 API 分組名稱。
//count:限流閾值
//intervalSec:統計時間窗口,單位是秒,默認是 1 秒。
rules.add(new GatewayFlowRule("order_route").setCount(2).setIntervalSec(1));
rules.add(new GatewayFlowRule("user_server_api").setCount(2).setIntervalSec(1));
// 加載網關規則
GatewayRuleManager.loadRules(rules);
}
}
其中網關限流規則 GatewayFlowRule 的字段解釋如下:
| 字段 | 解釋 |
|---|---|
| resource | 資源名稱,可以是網關中的 route 名稱或者用戶自定義的 API 分組名稱。 |
| resourceMode | 規則是針對 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)還是用戶在 Sentinel 中定義的 API 分組(RESOURCE_MODE_CUSTOM_API_NAME),默認是 route。 |
| grade | 限流指標維度,同限流規則的 grade 字段。 |
| count | 限流閾值 |
| intervalSec | 統計時間窗口,單位是秒,默認是 1 秒。 |
| controlBehavior | 流量整形的控制效果,同限流規則的 controlBehavior 字段,目前支持快速失敗和勻速排隊兩種模式,默認是快速失敗。 |
| burst | 應對突發請求時額外允許的請求數目。 |
| maxQueueingTimeoutMs | 勻速排隊模式下的最長排隊時間,單位是毫秒,僅在勻速排隊模式下生效。 |
| paramItem | 參數限流配置。若不提供,則代表不針對參數進行限流,該網關規則將會被轉換成普通流控規則;否則會轉換成熱點規則。 |
| paramItem - parseStrategy | 從請求中提取參數的策略,目前支持提取來源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 參數(PARAM_PARSE_STRATEGY_URL_PARAM)四種模式。 |
| paramItem - fieldName | 若提取策略選擇 Header 模式或 URL 參數模式,則需要指定對應的 header 名稱或 URL 參數名稱。 |
| paramItem - pattern | 參數值的匹配模式,只有匹配該模式的請求屬性值會納入統計和流控;若為空則統計該請求屬性的所有值。(1.6.2 版本開始支持) |
| paramItem - matchStrategy | 參數值的匹配策略,目前支持精確匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正則匹配(PARAM_MATCH_STRATEGY_REGEX)。(1.6.2 版本開始支持) |
用戶可以通過 GatewayRuleManager.loadRules(rules) 手動加載網關規則,或通過 GatewayRuleManager.register2Property(property) 注冊動態規則源動態推送(推薦方式)。
2.7 網關高可用
為了保證 Gateway 的高可用性,可以同時啟動多個 Gateway 實例進行負載,在 Gateway 的上游使用 Nginx 或者 F5 進行負載轉發以達到高可用。


