九男公、服務(wù)網(wǎng)關(guān):Gateway
9.1、網(wǎng)關(guān)簡(jiǎn)介
大家都都知道在微服務(wù)架構(gòu)中耘斩,一個(gè)系統(tǒng)會(huì)被拆分為很多個(gè)微服務(wù)沼填。那么作為客戶端要如何去調(diào)用這么多的微服務(wù)呢?如果沒(méi)有網(wǎng)關(guān)的存在括授,我們只能在客戶端記錄每個(gè)微服務(wù)的地址坞笙,然后分別去調(diào)用。
這樣的架構(gòu)會(huì)存在許多的問(wèn)題:
客戶端多次請(qǐng)求不同的微服務(wù)荚虚,增加客戶端代碼或配置編寫(xiě)的復(fù)雜性薛夜。
認(rèn)證復(fù)雜,每個(gè)服務(wù)都需要獨(dú)立認(rèn)證曲管。
-
存在跨域請(qǐng)求却邓,在一定場(chǎng)景下處理相對(duì)復(fù)雜。
網(wǎng)關(guān)就是為了解決這些問(wèn)題而生的院水。所謂的API網(wǎng)關(guān)腊徙,就是指系統(tǒng)的統(tǒng)一入口简十,它封裝了應(yīng)用程序的內(nèi)部結(jié)構(gòu),為客戶端提供統(tǒng)一服務(wù)撬腾,一些與業(yè)務(wù)本身功能無(wú)關(guān)的公共邏輯可以在這里實(shí)現(xiàn)螟蝙,諸如認(rèn)證、鑒權(quán)民傻、監(jiān)控胰默、路由轉(zhuǎn)發(fā)等等。
9.2漓踢、常用的網(wǎng)關(guān)
9.2.1牵署、Ngnix+lua
使用nginx的反向代理和負(fù)載均衡可實(shí)現(xiàn)對(duì)api服務(wù)器的負(fù)載均衡及高可用。
lua是一種腳本語(yǔ)言,可以來(lái)編寫(xiě)一些簡(jiǎn)單的邏輯, nginx支持lua腳本
9.2.2喧半、Kong
基于Nginx+Lua開(kāi)發(fā)奴迅,性能高,穩(wěn)定挺据,有多個(gè)可用的插件(限流取具、鑒權(quán)等等)可以開(kāi)箱即用。
他的缺點(diǎn):
- 只支持Http協(xié)議扁耐。
- 二次開(kāi)發(fā)暇检,自由擴(kuò)展困難。
- 提供管理API婉称,缺乏更易用的管控块仆、配置方式。
9.2.3酿矢、Zuul
Netflix開(kāi)源的網(wǎng)關(guān)榨乎,功能豐富,使用JAVA開(kāi)發(fā)瘫筐,易于二次開(kāi)發(fā)蜜暑。
他的缺點(diǎn):
- 缺乏管控,無(wú)法動(dòng)態(tài)配置策肝。
- 依賴組件較多肛捍。
- 處理Http請(qǐng)求依賴的是Web容器,性能不如Nginx之众。
9.2.4拙毫、Spring Cloud Gateway
Spring公司為了替換Zuul而開(kāi)發(fā)的網(wǎng)關(guān)服務(wù),SpringCloud alibaba技術(shù)棧中并沒(méi)有提供自己的網(wǎng)關(guān)棺禾,我們可以采用Spring Cloud Gateway來(lái)做網(wǎng)關(guān)
9.3缀蹄、Gateway簡(jiǎn)介
Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術(shù)開(kāi)發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單有效的統(tǒng)一的 API 路由管理方式缺前。它的目標(biāo)是替代Netflix Zuul蛀醉,其不僅提供統(tǒng)一的路由方式,并且基于 Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能衅码,例如:安全拯刁,監(jiān)控和限流。
他的主要功能是:
- 進(jìn)行轉(zhuǎn)發(fā)重定向逝段。
- 在開(kāi)始的時(shí)候垛玻,所有類都需要做的初始化操作。
- 進(jìn)行網(wǎng)絡(luò)隔離奶躯。
9.4帚桩、快速入門(mén)
需求:通過(guò)瀏覽器訪問(wèn)api網(wǎng)關(guān),然后通過(guò)網(wǎng)關(guān)將請(qǐng)求轉(zhuǎn)發(fā)到商品微服務(wù)。
9.4.1嘹黔、基礎(chǔ)版
創(chuàng)建一個(gè)api-gateway 模塊朗儒,并且導(dǎo)入下面的依賴。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
Shop-parent
<groupId>cn.linstudy</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
api-gateway
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!--gateway網(wǎng)關(guān)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
spring-cloud-starter-gateway
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
lombok
</dependency>
</dependencies>
</project>
復(fù)制代碼
編寫(xiě)配置文件
server:
port: 9000 # 指定網(wǎng)關(guān)服務(wù)的端口
spring:
application:
name: api-gateway
cloud:
gateway:
routes: # 路由數(shù)組[路由 就是指定當(dāng)請(qǐng)求滿足什么條件的時(shí)候轉(zhuǎn)到哪個(gè)微服務(wù)]
- id: product_route # 當(dāng)前路由的標(biāo)識(shí), 要求唯一
uri: http://localhost:8081 # 請(qǐng)求要轉(zhuǎn)發(fā)到的地址
order: 1 # 路由的優(yōu)先級(jí),數(shù)字越小級(jí)別越高
predicates: # 斷言(就是路由轉(zhuǎn)發(fā)要滿足的條件)
- Path=/product-serv/** # 當(dāng)請(qǐng)求路徑滿足Path指定的規(guī)則時(shí),才進(jìn)行路由轉(zhuǎn)發(fā)
filters: # 過(guò)濾器,請(qǐng)求在傳遞過(guò)程中可以通過(guò)過(guò)濾器對(duì)其進(jìn)行一定的修改
- StripPrefix=1 # 轉(zhuǎn)發(fā)之前去掉1層路徑
復(fù)制代碼
測(cè)試
9.4.2参淹、升級(jí)版
我們發(fā)現(xiàn)升級(jí)版有一個(gè)很大的問(wèn)題,那就是在配置文件中寫(xiě)死了轉(zhuǎn)發(fā)路徑的地址乏悄,我們需要在注冊(cè)中心來(lái)獲取地址浙值。
加入nacos依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
Shop-parent
<groupId>cn.linstudy</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
api-gateway
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!--gateway網(wǎng)關(guān)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
spring-cloud-starter-gateway
</dependency>
<!--nacos客戶端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
spring-cloud-starter-alibaba-nacos-discovery
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
lombok
</dependency>
</dependencies>
</project>
復(fù)制代碼
在主類上添加注解
@SpringBootApplication
@EnableDiscoveryClient
public class GateWayServerApp {
public static void main(String[] args) {
SpringApplication.run(GateWayServerApp.class,args);
}
}
復(fù)制代碼
修改配置文件
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 讓gateway可以發(fā)現(xiàn)nacos中的微服務(wù)
routes:
- id: product_route # 路由的名字
uri: lb://product-service # lb指的是從nacos中按照名稱獲取微服務(wù),并遵循負(fù)載均衡策略
predicates:
- Path=/product-serv/** # 符合這個(gè)規(guī)定的才進(jìn)行1轉(zhuǎn)發(fā)
filters:
- StripPrefix=1 # 將第一層去掉
復(fù)制代碼
我們還可以自定義多個(gè)路由規(guī)則。
spring:
application:
gateway:
routes:
- id: product_route
uri: lb://product-service
predicates:
- Path=/product-serv/**
filters:
- StripPrefix=1
- id: order_route
uri: lb://order-service
predicates:
- Path=/order-serv/**
filters:
- StripPrefix=1
復(fù)制代碼
9.4.3檩小、簡(jiǎn)寫(xiě)版
我們的配置文件無(wú)需寫(xiě)的1那么復(fù)雜就可以實(shí)現(xiàn)功能开呐,有一個(gè)簡(jiǎn)寫(xiě)版。
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true # 讓gateway可以發(fā)現(xiàn)nacos中的微服務(wù)
復(fù)制代碼
我們發(fā)現(xiàn)规求,就發(fā)現(xiàn)只要按照網(wǎng)關(guān)地址/微服務(wù)名稱/接口的格式去訪問(wèn)筐付,就可以得到成功響應(yīng)。
9.5阻肿、Gateway核心架構(gòu)
9.5.1瓦戚、基本概念
路由(Route) 是 gateway 中最基本的組件之一,表示一個(gè)具體的路由信息載體丛塌。主要定義了下面的幾個(gè)信息:
- id:路由標(biāo)識(shí)符较解,區(qū)別于其他 Route。
- uri:路由指向的目的地 uri赴邻,即客戶端請(qǐng)求最終被轉(zhuǎn)發(fā)到的微服務(wù)印衔。
- order:用于多個(gè) Route 之間的排序,數(shù)值越小排序越靠前姥敛,匹配優(yōu)先級(jí)越高奸焙。
- predicate:斷言的作用是進(jìn)行條件判斷,只有斷言都返回真,才會(huì)真正的執(zhí)行路由与帆。
- filter:過(guò)濾器用于修改請(qǐng)求和響應(yīng)信息了赌。
- predicate:斷言,用于進(jìn)行條件判斷鲤桥,只有斷言都返回真揍拆,才會(huì)真正的執(zhí)行路由。
9.5.2茶凳、執(zhí)行原理
- 接收用戶的請(qǐng)求嫂拴,請(qǐng)求處理器交給處理器映射器,返回執(zhí)行鏈贮喧。
- 請(qǐng)求處理器去調(diào)用web處理器筒狠,在web處理器里面對(duì)我們的路徑1進(jìn)行處理。假設(shè)1我們的路徑1是:http://localhost:9000/product-serv/get?id=1 箱沦,根據(jù)配置的路由規(guī)則辩恼,上本地找對(duì)應(yīng)的服務(wù)信息:product-service對(duì)應(yīng)的主機(jī)ip是192.168.10.130。
- 根據(jù)1ribbon的負(fù)載均衡策略去選擇一個(gè)節(jié)點(diǎn)谓形,然后拼接好灶伊,將路徑中的product-serv替換成192.168.10.130:8081,如果你配置了filter寒跳,那么他還會(huì)走filter聘萨。
- 如果你沒(méi)有自定義路由的話,默認(rèn)Gateway會(huì)幫你把第一層去掉童太。網(wǎng)關(guān)端口從此一個(gè)
/
開(kāi)始到第二個(gè)/
開(kāi)始算第一層米辐。
9.6、過(guò)濾器
Gateway的過(guò)濾器的作用是:是在請(qǐng)求的傳遞過(guò)程中,對(duì)請(qǐng)求和響應(yīng)做一些手腳书释。
Gateway的過(guò)濾器的生命周期:
PRE:這種過(guò)濾器在請(qǐng)求被路由之前調(diào)用翘贮。我們可利用這種過(guò)濾器實(shí)現(xiàn)身份驗(yàn)證、在集群中選擇 請(qǐng)求的微服務(wù)爆惧、記錄調(diào)試信息等狸页。
-
POST:這種過(guò)濾器在路由到微服務(wù)以后執(zhí)行械蹋。這種過(guò)濾器可用來(lái)為響應(yīng)添加標(biāo)準(zhǔn)的HTTP Header慢显、收集統(tǒng)計(jì)信息和指標(biāo)、將響應(yīng)從微服務(wù)發(fā)送給客戶端等乏德。
Gateway 的Filter從作用范圍可分為兩種: GatewayFilter與GlobalFilter:
GatewayFilter:應(yīng)用到單個(gè)路由或者一個(gè)分組的路由上叔收。
GlobalFilter:應(yīng)用到所有的路由上齿穗。
9.6.1、局部過(guò)濾器
局部過(guò)濾器是針對(duì)單個(gè)路由的過(guò)濾器饺律。他分為內(nèi)置過(guò)濾器和自定義過(guò)濾器窃页。
9.6.1.1、內(nèi)置過(guò)濾器
在SpringCloud Gateway中內(nèi)置了很多不同類型的網(wǎng)關(guān)路由過(guò)濾器。
9.6.1.1.1脖卖、局部過(guò)濾器內(nèi)容
過(guò)濾器工廠 | 作用 | 參數(shù) |
---|---|---|
AddRequestHeader | 為原始請(qǐng)求添加Header | Header的名稱及值 |
AddRequestParameter | 為原始請(qǐng)求添加請(qǐng)求參數(shù) | 參數(shù)名稱及值 |
AddResponseHeader | 為原始響應(yīng)添加Header | Header的名稱及值 |
DedupeResponseHeader | 剔除響應(yīng)頭中重復(fù)的值 | 需要去重的Header名稱及去重策略 |
Hystrix | 為路由引入Hystrix的斷路器保護(hù) | HystrixCommand 的名稱 |
FallbackHeaders | 為fallbackUri的請(qǐng)求頭中添加具體的異常信息 | Header的名稱 |
PrefixPath | 為原始請(qǐng)求路徑添加前綴 | 前綴路徑 |
PreserveHostHeader | 為請(qǐng)求添加一個(gè)preserveHostHeader=true的屬性乒省,路由過(guò)濾器會(huì)檢查該屬性以決定是否要發(fā)送原始的Host | 無(wú) |
RequestRateLimiter | 用于對(duì)請(qǐng)求限流,限流算法為令牌桶 | keyResolver畦木、rateLimiter袖扛、statusCode、denyEmptyKey十籍、emptyKeyStatus |
RedirectTo | 將原始請(qǐng)求重定向到指定的URL | http狀態(tài)碼及重定向的url |
RemoveHopByHopHeadersFilter | 為原始請(qǐng)求刪除IETF組織規(guī)定的一系列Header | 默認(rèn)就會(huì)啟用蛆封,可以通過(guò)配置指定僅刪除哪些Header |
RemoveRequestHeader | 為原始請(qǐng)求刪除某個(gè)Header | Header名稱 |
RemoveResponseHeader | 為原始響應(yīng)刪除某個(gè)Header | Header名稱 |
RewritePath | 重寫(xiě)原始的請(qǐng)求路徑 | 原始路徑正則表達(dá)式以及重寫(xiě)后路徑的正則表達(dá)式 |
RewriteResponseHeader | 重寫(xiě)原始響應(yīng)中的某個(gè)Header | Header名稱,值的正則表達(dá)式勾栗,重寫(xiě)后的值 |
SaveSession | 在轉(zhuǎn)發(fā)請(qǐng)求之前惨篱,強(qiáng)制執(zhí)行WebSession::save 操作 |
無(wú) |
secureHeaders | 為原始響應(yīng)添加一系列起安全作用的響應(yīng)頭 | 無(wú),支持修改這些安全響應(yīng)頭的值 |
SetPath | 修改原始的請(qǐng)求路徑 | 修改后的路徑 |
SetResponseHeader | 修改原始響應(yīng)中某個(gè)Header的值 | Header名稱围俘,修改后的值 |
SetStatus | 修改原始響應(yīng)的狀態(tài)碼 | HTTP 狀態(tài)碼砸讳,可以是數(shù)字,也可以是字符串 |
StripPrefix | 用于截?cái)嘣颊?qǐng)求的路徑 | 使用數(shù)字表示要截?cái)嗟穆窂降臄?shù)量 |
Retry | 針對(duì)不同的響應(yīng)進(jìn)行重試 | retries界牡、statuses簿寂、methods、series |
RequestSize | 設(shè)置允許接收最大請(qǐng)求包的大小宿亡。如果請(qǐng)求包大小超過(guò)設(shè)置的值陶耍,則返回 413 Payload Too Large | 請(qǐng)求包大小,單位為字節(jié)她混,默認(rèn)值為5M |
ModifyRequestBody | 在轉(zhuǎn)發(fā)請(qǐng)求之前修改原始請(qǐng)求體內(nèi)容 | 修改后的請(qǐng)求體內(nèi)容 |
ModifyResponseBody | 修改原始響應(yīng)體的內(nèi)容 | 修改后的響應(yīng)體內(nèi)容 |
9.6.1.1.2、局部過(guò)濾器的使用
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 讓gateway可以發(fā)現(xiàn)nacos中的微服務(wù)
routes:
- id: product_route # 路由的名字
uri: lb://product-service # lb指的是從nacos中按照名稱獲取微服務(wù),并遵循負(fù)載均衡策略
predicates:
- Path=/product-serv/** # 符合這個(gè)規(guī)定的才進(jìn)行1轉(zhuǎn)發(fā)
filters:
- StripPrefix=1 # 將第一層去掉
- SetStatus=2000 # 這里使用內(nèi)置的過(guò)濾器泊碑,修改返回狀態(tài)
復(fù)制代碼
9.6.1.2坤按、自定義局部過(guò)濾器
很多的時(shí)候,內(nèi)置過(guò)濾器沒(méi)辦法滿足我們的需求馒过,這個(gè)時(shí)候就必須自定義局部過(guò)濾器臭脓。我們假定一個(gè)需求是:統(tǒng)計(jì)訂單服務(wù)調(diào)用耗時(shí)。
編寫(xiě)一個(gè)類腹忽,用于實(shí)現(xiàn)邏輯
**名稱是有固定格式xxxGatewayFilterFactory**
@Component
public class TimeGatewayFilterFactory extends AbstractGatewayFilterFactory<TimeGatewayFilterFactory.Config> {
private static final String BEGIN_TIME = "beginTime";
//構(gòu)造函數(shù)
public TimeGatewayFilterFactory() {
super(TimeGatewayFilterFactory.Config.class);
}
//讀取配置文件中的參數(shù) 賦值到 配置類中
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("show");
}
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (!config.show){
// 如果配置類中的show為false来累,表示放行
return chain.filter(exchange);
}
exchange.getAttributes().put(BEGIN_TIME, System.currentTimeMillis());
/**
* pre的邏輯
* chain.filter().then(Mono.fromRunable(()->{
* post的邏輯
* }))
*/
return chain.filter(exchange).then(Mono.fromRunnable(()->{
Long startTime = exchange.getAttribute(BEGIN_TIME);
if (startTime != null) {
System.out.println(exchange.getRequest().getURI() + "請(qǐng)求耗時(shí): " + (System.currentTimeMillis() - startTime) + "ms");
}
}));
}
};
}
@Setter
@Getter
static class Config{
private boolean show;
}
}
復(fù)制代碼
編寫(xiě)application.xml
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 讓gateway可以發(fā)現(xiàn)nacos中的微服務(wù)
routes:
- id: product_route # 路由的名字
uri: lb://product-service # lb指的是從nacos中按照名稱獲取微服務(wù),并遵循負(fù)載均衡策略
predicates:
- Path=/product-serv/** # 符合這個(gè)規(guī)定的才進(jìn)行1轉(zhuǎn)發(fā)
filters:
- StripPrefix=1 # 將第一層去掉
- id: order_route
uri: lb://order-service
predicates:
- Path=/order-serv/**
filters:
- StripPrefix=1
- Time=true
復(fù)制代碼
訪問(wèn)路徑:http://localhost:9000/order-serv/getById?o=1&pid=1
9.6.2、全局過(guò)濾器
全局過(guò)濾器作用于所有路由, 無(wú)需配置窘奏。通過(guò)全局過(guò)濾器可以實(shí)現(xiàn)對(duì)權(quán)限的統(tǒng)一校驗(yàn)嘹锁,安全性驗(yàn)證等功能。SpringCloud Gateway內(nèi)部也是通過(guò)一系列的內(nèi)置全局過(guò)濾器對(duì)整個(gè)路由轉(zhuǎn)發(fā)進(jìn)行處理着裹。
開(kāi)發(fā)中的鑒權(quán)邏輯:
- 當(dāng)客戶端第一次請(qǐng)求服務(wù)時(shí)领猾,服務(wù)端對(duì)用戶進(jìn)行信息認(rèn)證(登錄)。
- 認(rèn)證通過(guò),將用戶信息進(jìn)行加密形成token摔竿,返回給客戶端面粮,作為登錄憑證。
- 以后每次請(qǐng)求继低,客戶端都攜帶認(rèn)證的token熬苍。
- 服務(wù)端對(duì)token進(jìn)行解密,判斷是否有效袁翁。
我們來(lái)模擬一個(gè)需求:實(shí)現(xiàn)統(tǒng)一鑒權(quán)的功能,我們需要在網(wǎng)關(guān)判斷請(qǐng)求中是否包含token且柴底,如果沒(méi)有則不轉(zhuǎn)發(fā)路由,有則執(zhí)行正常邏輯梦裂。
編寫(xiě)全局過(guò)濾器
@Component
public class AuthGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (StringUtils.isBlank(token)) {
System.out.println("鑒權(quán)失敗");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
復(fù)制代碼
9.6.3似枕、網(wǎng)關(guān)限流
網(wǎng)關(guān)是所有請(qǐng)求的公共入口,所以可以在網(wǎng)關(guān)進(jìn)行限流年柠,而且限流的方式也很多凿歼,我們本次采用前面學(xué)過(guò)的Sentinel組件來(lái)實(shí)現(xiàn)網(wǎng)關(guān)的限流。Sentinel支持對(duì)SpringCloud Gateway冗恨、Zuul等主流網(wǎng)關(guān)進(jìn)行限流答憔。
從1.6.0版本開(kāi)始,Sentinel提供了SpringCloud Gateway的適配模塊掀抹,可以提供兩種資源維度的限流:
- route維度:即在Spring配置文件中配置的路由條目虐拓,資源名為對(duì)應(yīng)的routeId
- 自定義API維度:用戶可以利用Sentinel提供的API來(lái)自定義一些API分組
9.6.3.1、網(wǎng)關(guān)集成Sentinel
添加依賴
<dependency>
<groupId>com.alibaba.csp</groupId>
sentinel-spring-cloud-gateway-adapter
</dependency>
復(fù)制代碼
編寫(xiě)配置類進(jìn)行限流
配置類的本質(zhì)是用代碼替代nacos圖形化界面限流傲武。
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
// 配置限流的異常處理器
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
// 初始化一個(gè)限流的過(guò)濾器
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
//增加對(duì)商品微服務(wù)的限流
@PostConstruct
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("product_route")
.setCount(3) // 三次
.setIntervalSec(1) // 一秒蓉驹,表示一秒鐘1超過(guò)了三次就會(huì)限流
);
GatewayRuleManager.loadRules(rules);
}
}
復(fù)制代碼
修改限流默認(rèn)返回格式
如果我們不想在限流的時(shí)候返回默認(rèn)的錯(cuò)誤,那么就需要自定義錯(cuò)誤揪利,指定自定義的返回格式态兴。我們只需在類中添加一段配置即可。
@PostConstruct
public void initBlockHandlers() {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
Map map = new HashMap<>();
map.put("code", 0);
map.put("message", "接口被限流了");
return ServerResponse.status(HttpStatus.OK).
contentType(MediaType.APPLICATION_JSON).
body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
復(fù)制代碼
測(cè)試
9.6.3.2疟位、自定義API分組
我們可以發(fā)現(xiàn)瞻润,上面的這種定義,對(duì)整個(gè)服務(wù)進(jìn)行了限流甜刻,粒度不夠細(xì)绍撞。自定義API分組是一種更細(xì)粒度的限流規(guī)則定義,它可以實(shí)現(xiàn)某個(gè)方法的細(xì)粒度限流得院。
在Shop-order-server項(xiàng)目中添加ApiController
@RestController
@RequestMapping("/api")
public class ApiController {
@RequestMapping("/hello")
public String api1(){
return "api";
}
}
復(fù)制代碼
在GatewayConfiguration中添加配置
@PostConstruct
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("order_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/order-serv/api/**"). setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
@PostConstruct
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("product_route")
.setCount(3)
.setIntervalSec(1)
);
rules.add(new GatewayFlowRule("order_api").
setCount(1).
setIntervalSec(1));
GatewayRuleManager.loadRules(rules);
}
復(fù)制代碼
測(cè)試
直接訪問(wèn)[http://localhost:8082/api/hello](https://link.juejin.cn?target=http%3A%2F%2Flocalhost%3A8082%2Fapi%2Fhello "http://localhost:8082/api/hello") 是不會(huì)發(fā)生限流的傻铣,訪問(wèn)[http://localhost:9000/order-serv/api/hello](https://link.juejin.cn?target=http%3A%2F%2Flocalhost%3A9000%2Forder-serv%2Fapi%2Fhello "http://localhost:9000/order-serv/api/hello") 就會(huì)出現(xiàn)限流了。
作者:XiaoLin_Java
鏈接:https://juejin.cn/post/7001816849826447397
來(lái)源:稀土掘金
著作權(quán)歸作者所有祥绞。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)矾柜,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處阱驾。
微信公眾號(hào)【程序員黃小斜】作者是前螞蟻金服Java工程師,專注分享Java技術(shù)干貨和求職成長(zhǎng)心得怪蔑,不限于BAT面試里覆,算法、計(jì)算機(jī)基礎(chǔ)缆瓣、數(shù)據(jù)庫(kù)喧枷、分布式、spring全家桶弓坞、微服務(wù)隧甚、高并發(fā)、JVM渡冻、Docker容器戚扳,ELK、大數(shù)據(jù)等族吻。關(guān)注后回復(fù)【book】領(lǐng)取精選20本Java面試必備精品電子書(shū)帽借。