本系列筆記涉及到的代碼在GitHub上,地址:https://github.com/zsllsz/cloud
本文涉及知識點:
服務降級熔斷之hystrix;
服務網(wǎng)關之gateway;
歡迎大家關注我的公眾號 javawebkf,目前正在慢慢地將簡書文章搬到公眾號,以后簡書和公眾號文章將同步更新,且簡書上的付費文章在公眾號上將免費。
一、服務降級&熔斷&限流之Hystrix(豪豬)
1、微服務面臨的問題:
將一個個的業(yè)務拆分出來,獨立成一個個服務,降低了系統(tǒng)的耦合度,但是也面臨了一些問題。比如實現(xiàn)業(yè)務場景一需要調(diào)用服務A,A又要調(diào)用B,B還要調(diào)用C……,這叫做“扇出”,就是各個微服務相互調(diào)用,像一把折扇一樣。如果B掛了,那就導致整條鏈路不能用了,就出現(xiàn)了服務雪崩的情況。為了解決這種問題,就需要一種名為“服務降級和熔斷”的辦法。
2、Hystrix是什么?
Hystrix就是服務降級和熔斷的一種落地實現(xiàn)??梢员WC當某個服務超時、異常的情況下,不會導致整體服務雪崩,避免級聯(lián)故障,提高分布式系統(tǒng)的彈性。它會在當某個服務超時、異常的時候,返回一個符合預期格式、可處理的備選響應給調(diào)用者,從而保證了服務的可用。
3、Hystrix能干嘛:
- 服務降級:fallback,比如我們寫代碼的時候,有下面這種情況:
if () {
} else if () {
} else {
}
這里最后的else就是服務降級,就是給一個兜底的解決方案。 會發(fā)生服務降級的情況:程序異常、響應超時、服務熔斷觸發(fā)降級、線程池/信號量打滿也會導致服務降級。
服務熔斷:break,就像保險絲熔斷一樣,當服務達到了所能承受的最大訪問量后,就拉閘斷電,調(diào)用服務降級給用戶返回友好的提示。
服務限流:flowlimit,在秒殺等高并發(fā)的場景下,嚴禁一窩蜂地訪問系統(tǒng),而是排隊訪問,一秒鐘N個,有序進行。
4、cloud-provider-hystrix-payment8001項目搭建:
新建一個名為cloud-provider-hystrix-payment8001的module。
- pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- application.yml:
server:
port: 8001
spring:
application:
name: cloud-provider-hystrix-payment
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka #eureka server
- 啟動類:
@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
public static void main(String[] args) throws Exception {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
- service:
@Service
public class PaymentService {
public String paymentOk(Integer id) {
return " thats ok";
}
public String paymentError(Integer id) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "somethind wrong";
}
}
這里一個方法模擬正常情況,一個方法模擬超時的情況。然后在controller中調(diào)這兩個方法。
- controller:
@RestController
@RequestMapping("/payment")
public class PaymentController {
@Autowired
private PaymentService paymentService;
@Value("${server.port}")
private String port;
@GetMapping("/ok/{id}")
public String paymentOk(@PathVariable("id") Integer id) {
return paymentService.paymentOk(id) + "\r\n" + port;
}
@GetMapping("/error/{id}")
public String paymentError(@PathVariable("id") Integer id) {
return paymentService.paymentError(id) + "\r\n" + port;
}
}
啟動7001的eureka server和這個8001,訪問從controller中的兩個接口,測試一下。在非高并發(fā)的情況下,兩個接口都可以正常返回數(shù)據(jù),只不過paymentOk可以立即響應,而paymentError就要等待5秒才會響應。但是,如果搞個jmeter對paymentError接口進行壓測,20000個線程并發(fā)去請求paymentError,然后你再用瀏覽器訪問paymentOk,發(fā)現(xiàn)paymentOk也被拖慢了。如果線程再多一點兒,可能就會訪問不了了??擅髅魇莗aymentError接口響應慢,paymentOk是不應該受影響的。所以可以用hystrix對服務進行降級。下面先新建一個consumer調(diào)用這個payment服務,然后再在這個consumer中對服務進行降級。
5、cloud-consumer-feign-hystrix-order80項目搭建:
新建名為cloud-consumer-feign-hystrix-order80的module。
- pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- yml:
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka
- 主啟動類:
@SpringBootApplication
@EnableFeignClients
public class OrderHystrixMain80 {
public static void main(String[] args) throws Exception {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
- service:
@Service
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
@GetMapping("payment/ok/{id}")
public String paymentOk(@PathVariable("id") Integer id);
@GetMapping("payment/error/{id}")
public String paymentError(@PathVariable("id") Integer id);
}
- controller:
@RestController
@RequestMapping("/order")
public class OrderHystrixController {
@Autowired
private PaymentHystrixService phService;
@GetMapping("/hystrix/ok/{id}")
public String paymentOk(@PathVariable("id") Integer id) {
return phService.paymentOk(id);
}
@GetMapping("/hystrix/error/{id}")
public String paymentError(@PathVariable("id") Integer id) {
return phService.paymentError(id);
}
}
啟動后,通過瀏覽器訪問http://localhost/order/hystrix/ok/1,發(fā)現(xiàn)是立即響應的,訪問http://localhost/order/hystrix/error/1發(fā)現(xiàn)報500了,控制臺報錯 Read timed out。這是因為openfeign默認超時時間是1秒,而error接口又設置了線程睡5秒??梢栽趏rder80的配置文件中配置openfeign超時時間,設置大于5秒,就可以正常訪問。
ribbon:
# 建立連接后從服務器獲取可用資源的時間
ReadTimeout: 6000
# 建立連接所有的時間
ConnectTimeout: 6000
這是沒有并發(fā)的情況,再使用jmeter進行壓測,那么這兩個接口都得涼涼了。
6、如何解決上面的問題?
服務提供方payment8001:
- 如果8001超時,不能讓order80一直轉(zhuǎn)圈圈等待,要進行payment8001服務降級
- 如果8001掛掉了,也不能讓order80一直等待,要進行payment8001服務降級
服務調(diào)用方order80:
- 如果payment8001沒問題,order80自己出故障了,那么order80要進行服務降級
7、payment8001服務降級配置:
payment8001的paymentError方法,線程睡了5秒,所以至少5秒才會有響應。假設我們認為這個方法正常是3秒就能響應完的,超過3秒就要進行服務降級。那么我們就設置超時時間峰值為3秒,超過了3秒就要有兜底的方法。
- 首先在啟動類上加上@EnableCircuitBreaker注解激活hystrix功能;
- 然后在paymentError方法上加上@HystrixCommand注解,并且配置超時調(diào)用的方法,如下:
@HystrixCommand(fallbackMethod = "paymentError_default", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentError(Integer id) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "somethind wrong";
}
public String paymentError_default(Integer id) {
return "這是兜底的方法";
}
這段代碼的意思就是,paymentError方法至少要5秒才會響應,但是我加上了hystrix的注解,設置了最大響應時長為3秒,超過3秒,那就走兜底的方法。所以現(xiàn)在啟動payment8001訪問paymentError方法,應該會打出"這是兜底的方法"這句話。

說明hystrix配置成功了,并且除了超時,如果paymentError報異常了,比如寫一個
int x = 10 / 0,也會走兜底的方法。
8、消費端order80的服務降級:
消費端服務降級也一樣的配置,在主啟動類上加@EnableCircuitBreaker注解,然后controller寫成下面這樣:
@GetMapping("/hystrix/error/{id}")
@HystrixCommand(fallbackMethod = "paymentError_default", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentError(@PathVariable("id") Integer id) {
return phService.paymentError(id);
}
public String paymentError_default(@PathVariable("id")Integer id) {
return "這是消費端兜底的方法";
}
配置超過3秒就走兜底的方法。而服務端payment8001對應的方法設置了線程睡5秒,超過了3秒才會有響應,所以這里會走兜底的方法。注意ribbon默認超時時間是1秒,所以如果修改ribbon超時時間的話,即使payment8001中設置線程睡2秒,order80中hystrix配置超時時間3秒,也會走兜底的方法,因為是否超時優(yōu)先取的是ribbon配置的。
9、全局降級配置:
上面針對需要服務降級的兩個方法加上了hystrix相關配置,如果還有大量的方法也需要服務降級,在每個方法上都加上這么一段注解,不太方便,所以就出現(xiàn)了全局降級配置。比如要在order80上做全局服務降級配置,只需要將controller改成下面這樣即可:
@RestController
@RequestMapping("/order")
@DefaultProperties(defaultFallback = "defaultMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public class OrderHystrixController {
@Autowired
private PaymentHystrixService phService;
@GetMapping("/hystrix/ok/{id}")
@HystrixCommand
public String paymentOk(@PathVariable("id") Integer id) {
return phService.paymentOk(id);
}
@GetMapping("/hystrix/error/{id}")
@HystrixCommand(fallbackMethod = "paymentError_default", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentError(@PathVariable("id") Integer id) {
return phService.paymentError(id);
}
public String paymentError_default(@PathVariable("id")Integer id) {
return "這是消費端兜底的方法";
}
public String defaultMethod() {
return "我是全局默認的服務降級配置";
}
}
首先在類上加注解,并配置超時時間,然后需要用全局降級的方法上加@HystrixCommand注解。這里用paymentOk方法來演示,payment8001端的paymentOk方法也設置線程睡4秒鐘,paymentOk方法應該會打印出“我是全局默認的服務降級配置”這句話。

然后將payment8001的paymentOk方法改成睡2秒鐘,那么就會正常返回:

然后paymentError方法,因為在方法上配置了hystrix相關配置,所以還是走方法對應的配置,而不是走全局。
但是以上做法還是不夠完美,因為order80調(diào)用payment8001,所有接口都是通過openfeign去調(diào)用的,擒賊先擒王,所以最好的做法就是在openfeign調(diào)用payment8001的接口中添加實現(xiàn)去做降級。具體做法如下:
- 修改yml:
feign:
hystrix:
enabled: true
- order80的service改成這樣:
@Service
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentHystrixServiceImpl.class)
public interface PaymentHystrixService {
@GetMapping("payment/ok/{id}")
public String paymentOk(@PathVariable("id") Integer id);
@GetMapping("payment/error/{id}")
public String paymentError(@PathVariable("id") Integer id);
}
- 新建service的實現(xiàn):
@Component
public class PaymentHystrixServiceImpl implements PaymentHystrixService{
@Override
public String paymentOk(Integer id) {
return "paymentOk-default-return";
}
@Override
public String paymentError(Integer id) {
return "paymentError-default-return";
}
}
- 最后把controller中hystrix相關注解都去掉。
這樣就搞定了,當訪問8001發(fā)生異常、或者8001壓根兒就沒啟動時,就會執(zhí)行serviceImpl里面的方法。
10、服務熔斷:
當微服務調(diào)用鏈路的某個服務不可用了或者響應時間太長了,會對服務進行降級,快速返回友好的響應信息,當檢測到該節(jié)點正常了之后,又會恢復調(diào)用。即一開始是close狀態(tài),檢測到異常就變成open狀態(tài),然后再變成half open狀態(tài),恢復一部分調(diào)用,如果沒問題再變成close。下面就演示服務熔斷。
- 首先在payment8001的service中加如下代碼:
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 是否開啟斷路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 請求次數(shù)
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 時間窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), // 失敗率達到多少后跳閘
// 10次請求有6次是失敗的,就進行服務熔斷,10秒后會變?yōu)閔alf open狀態(tài),看看能否請求成功,如果成功就變成close狀態(tài)
})
public String paymentCircuitBreaker(Integer id) {
if (id < 0) {
throw new RuntimeException("id不能為負數(shù)");
}
return "調(diào)用成功";
}
public String paymentCircuitBreaker_fallback(Integer id) {
return "id不能為負數(shù)";
}
這幾個注解的意思就是在10次訪問中,如果失敗了6次,那就熔斷,返回“id不能為負數(shù)這句話”,這個時候,即使你傳的id是正數(shù),也會返回這句話,因為這個時候服務熔斷了。10000 milliseconds后,會變成半開狀態(tài),試著放行一個請求,如果此時你請求的id是正數(shù),那么就返回“調(diào)用成功”,并且解除熔斷。
- 在controller中新增如下方法:
@GetMapping("/breaker/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
return paymentService.paymentCircuitBreaker(id);
}
可以訪問該接口,先傳入負數(shù)id,然后滿足10次有6次失敗的情況下,再將id變?yōu)檎龜?shù)傳入,發(fā)現(xiàn)也是返回“id不能為負數(shù)”這句話。過一段時間后才恢復正常,說明服務熔斷起作用了。
11、hystrix的圖形化界面:
- 新建一個cloud-consumer-hystrix-dashboard9001的module
- pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator </artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix-dashboard -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
- 主啟動類:
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashBoardMain9001 {
public static void main(String[] args) throws Exception {
SpringApplication.run(HystrixDashBoardMain9001.class, args);
}
}
- 如果要監(jiān)控8001,那么需要在8001中配置如下bean:
@Configuration
public class DashBoardConfig {
@Bean
public ServletRegistrationBean<HystrixMetricsStreamServlet> getBean() {
HystrixMetricsStreamServlet bean = new HystrixMetricsStreamServlet();
ServletRegistrationBean<HystrixMetricsStreamServlet> register = new ServletRegistrationBean<HystrixMetricsStreamServlet>(bean);
register.setLoadOnStartup(1);
register.addUrlMappings("/hystrix.stream");
register.setName("HystrixMetricsStreamServlet");
return register;
}
}
-
然后訪問 localhost:9001/hystrix,在頁面中填寫如下信息:
dashboard
填好后回車,然后再去訪問8001,那么8001的訪問信息就會出現(xiàn)在dashboard中了。
dashboard
二、服務網(wǎng)關之spring gateway
1、服務網(wǎng)關是來干嘛的?
一般來說,用戶訪問首先是到nginx,nginx會做負載均衡,然后并不是直接訪問各位微服務應用,而是先到gateway。gateway可以做路由轉(zhuǎn)發(fā)、權限校驗、流量控制等。功能類似的框架還有zuul和zuul2,zuul停更了,zuul2還沒完善出來,所以spring自己搞了一套gateway。
2、gateway核心概念:
- 路由Route:簡單的理解為url,如果斷言為true就匹配該url
- 斷言Predicate:路由轉(zhuǎn)發(fā)的判斷條件
- 過濾Filter:過濾器
3、gateway工作流程:
核心邏輯是路由轉(zhuǎn)發(fā) + 執(zhí)行過濾鏈。客戶端向gateway發(fā)請求,然后在gateway handler mapping 找到相匹配的路由,將請求發(fā)送到gateway web handler,handler再通過過濾鏈將請求發(fā)送到微服務中,然后返回。
4、代碼演示:
- 新建名為cloud-gateway-gateway9527的module;
- pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- yml:
server:
port: 9527
spring:
application:
name: cloud-gateway
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
instance:
instance-id: cloud-gateway
prefer-ip-address: true
- 主啟動:
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) throws Exception {
SpringApplication.run(GatewayMain9527.class, args);
}
}
8001的controller中有兩個接口,現(xiàn)在我們可以直接通過接口路由訪問到,但是我不想暴露8001端口,想通過9527端口去訪問,做法如下:
- 將9527的yml改成下面這樣:
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_route # id,要求唯一
uri: http://localhost:8001 #提供服務的路由地址
predicates:
- Path=/payment/ok/** # 路徑匹配的進行路由
- id: payment_route # id,要求唯一
uri: http://localhost:8001 #提供服務的路由地址
predicates:
- Path=/payment/error/** # 路徑匹配的進行路由
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
instance:
instance-id: cloud-gateway
prefer-ip-address: true
現(xiàn)在依次啟動7001的eureka、8001的payment和9527的gateway,然后訪問呢localhost:9527/payment/ok/1,發(fā)現(xiàn)可以訪問成功,說明路由轉(zhuǎn)發(fā)成功。
這是配置網(wǎng)關的第一種方式,還有硬編碼的方式,如下:
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
// 意思就是訪問localhost:9527/domestic將會轉(zhuǎn)發(fā)到https://tuijian.hao123.com/domestic中去
routes.route("path_id", r -> r.path("/domestic").uri("https://tuijian.hao123.com/domestic")).build();
return routes.build();
}
}
現(xiàn)在訪問localhost:9527/domestic,結果如下:

5、動態(tài)路由:
提供payment服務的有8001和8002,但是上面那樣配置只寫了8001,現(xiàn)在要實現(xiàn)通過微服務名稱來做動態(tài)路由。即在配置那里不寫死8001或8002,而是寫8001和8002的微服務名稱,這樣就可以實現(xiàn)動態(tài)路由。
- 首先確保啟動了8001和8002;
- 改yml:
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 開啟從注冊中心動態(tài)創(chuàng)建路由的功能
routes:
- id: payment_route1 # id,要求唯一
#uri: http://localhost:8001 #提供服務的路由地址
uri: lb://CLOUD-PAYMENT-SERVICE #微服務名稱
predicates:
- Path=/payment/** # 路徑匹配的進行路由
- id: payment_route2 # id,要求唯一
#uri: http://localhost:8001 #提供服務的路由地址
uri: lb://CLOUD-PAYMENT-SERVICE #微服務名稱
predicates:
- Path=/payment/** # 路徑匹配的進行路由
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
instance:
instance-id: cloud-gateway
prefer-ip-address: true
就這樣就行了,然后訪問http://localhost:9527/payment/1,就可以成功訪問到8001和8002,并且會進行負載均衡,一次8001,一次8002,輪著來。
6、常用斷言:
predicates:
- Path=/payment/** # 路徑匹配的進行路由
- After=2020-05-04T20:47:11.281+08:00[Asia/Shanghai] # 配置的規(guī)則要在2020年5月4日20點20分后才生效,有after就有before和between
- Cookie=username,test # 必須帶cookie訪問,cookie名叫username,值為test,值也可以寫正則表達式
- Header=X-Request-Id,\d+ # 必須帶請求頭訪問,請求頭名為X-Request-Id,值要滿足 \d+ 這個正則表達式
- Host=**.somehost.com,**.otherhost.com #請求域名必須匹配這兩個,即請求時添加header,名為host,值匹配這兩個即可
- Method=GET #必須是get請求
- Query=id,\d+ #必須有名為id的參數(shù)且值匹配 \d+ 這個正則
7、常用filter:
filter生命周期有兩種,一種是在業(yè)務邏輯之前,一種是在業(yè)務邏輯之后;種類也是兩種,一種gatewayFilter,一種globalFilter。用法和predicates一樣,比如:
filters:
- AddRequestParameter=X-Request-Id,1024 # 請求必須帶名為X-Request-Id的請求頭,值為1024
8、自定義過濾器:
可以實現(xiàn)全局日志記錄,統(tǒng)一網(wǎng)關鑒權等功能。
- 新建自定義過濾器類:
@Component
@Slf4j
public class MyFilter implements GlobalFilter, Ordered{
/**
* 表示這個過濾器的優(yōu)先級,數(shù)字越小優(yōu)先級越高
*/
@Override
public int getOrder() {
return 0;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("=================進去自定義全局過濾器=============");
// 獲取id參數(shù)
String id = exchange.getRequest().getQueryParams().getFirst("id");
if (!"1".equals(id)) {
log.error("================= id不存在==================");
// 設置返回碼
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
也就是說,如果沒有id這個參數(shù)或者id參數(shù)值不為1的,都會被攔截。實際生產(chǎn)中可以用這個來驗證請求是否攜帶token。

