一、網關介紹
1、什麼是網關?
使⽤服務⽹關作爲接⼝服務的統⼀代理,前端通過⽹關完成服務的統⼀調⽤
2、⽹關可以⼲什麼?
路由:接⼝服務的統⼀代理,實現前端對接⼝服務的統⼀訪問過濾:對⽤戶請求進⾏攔截、過濾(⽤戶鑑權)、監控限流:限制⽤戶的訪問流量
3、常⽤的⽹關
NginxSpring Cloud Netflix zuulSpring Cloud Gateway
二、使⽤Nginx實現⽹關服務
Nginx通常被⽤作應⽤服務器⽹關,服務⽹關通常使⽤zuul或者gateway
三、使用Zuul實現網關服務
四、使用Gateway實現網關服務
1、搭建gateway服務器
創建SpringBoot應⽤,添加gateway依賴
2、配置路由規則
application.ymlserver: port: 9999 spring: application: name: gateway-server cloud: gateway: routes: # 配置api-service1路由規則 - id: api-service1 uri: 'http://localhost:8001' predicates: - Path=/product/** # 配置api-service2路由規則 - id: api-service2 uri: 'http://localhost:8002' predicates: - Path=/order/**
五、Gateway⼯作原理
1、名詞解釋
Route: 路由是⽹關的基本組成部分,它是由id、⽬標uri、斷⾔組成,如果斷⾔爲true,則匹配該路由,轉向到當前路由的URIPredicate:斷⾔,⽤戶請求的匹配規則Filter:過濾器,⽤於對請求進⾏前置、後置處理(可以在⽹關實現對請求或相應的加⼯處理)
2、Gateway⼯作流程圖
六、Predicate斷⾔
SpringCloud Gateway提供了多種斷⾔匹配的⽅式:
- After
- Before
- Between
- Cookie
- Header
- Host
- Method
- Path
- Query
- RemoteAddr
- Weight
1、Path
根據請求路徑的正則匹配
spring: application: null name: gateway-server cloud: null gateway: null routes: - id: aaa uri: 'http://localhost:8001' predicates: - Path=/product/** - id: bbb uri: 'http://localhost:8002' predicates: - Path=/order/**
2、Query
根據請求攜帶的參數匹配路由
spring: application: name: gateway-server cloud: gateway: routes: - id: aaa uri: 'http://localhost:8001' predicates: # 如果請求url中帶有name參數 ---> http://localhost:8001 - Query=name - id: bbb uri: 'http://localhost:8002' predicates: #如果請求url中帶有pwd參數 ---> http://localhost:8002 - Query=pwd
3、Header
根據Header中攜帶的參數匹配
spring: application: name: gateway-server cloud: gateway: routes: - id: aaa uri: 'http://localhost:8001' predicates: - Header=token - id: bbb uri: 'http://localhost:8002' predicates: - 'Header=aa,haha'
七、過濾器
1、Gateway內置⽹關過濾器
gateway⽹關可以對⽤戶的請求和響應進⾏處理,gateway提供了多個內置的過濾器,不同的過濾器可以完成不同的請求或者響應的處理1. AddRequestHeader 在請求頭中添加參數2. AddRequestParameter 添加請求參數3. AddResponseHeader4. The DedupeResponseHeader GatewayFilter Factory5. The Hystrix GatewayFilter Factory6. Spring Cloud CircuitBreaker GatewayFilter Factory7. The FallbackHeaders GatewayFilter Factory8. The MapRequestHeader GatewayFilter Factory9. The PrefixPath GatewayFilter Factory10. The PreserveHostHeader GatewayFilter Factory11. The RequestRateLimiter GatewayFilter Factory12. The RedirectTo GatewayFilter Factory13. The RemoveRequestHeader GatewayFilter Factory14. RemoveResponseHeader GatewayFilter Factory15. The RemoveRequestParameter GatewayFilter Factory16. The RewritePath GatewayFilter Factory17. RewriteLocationResponseHeader GatewayFilter Factory18. The RewriteResponseHeader GatewayFilter Factory19. The SaveSession GatewayFilter Factory20. The SecureHeaders GatewayFilter Factory21. The SetPath GatewayFilter Factory22. The SetRequestHeader GatewayFilter Factory23. The SetResponseHeader GatewayFilter Factory24. The SetStatus GatewayFilter Factory25. The StripPrefix GatewayFilter Factory26. The Retry GatewayFilter Factory27. The RequestSize GatewayFilter Factory28. The SetRequestHostHeader GatewayFilter Factory29. Modify a Request Body GatewayFilter Factory30. Modify a Response Body GatewayFilter Factory31. Default Filters
spring: application: name: gateway-server cloud: gateway: routes: - id: aaa uri: 'http://localhost:8001' predicates: - Path=/red/aaa/product/** filters: - 'AddRequestHeader=token,wahahaawahaha' - 'AddRequestParameter=username, ergou' - SetStatus=404 - StripPrefix=2
2、⾃定義服務過濾器
2.1、創建⽹關過濾器 - 實現GatewayFilter
1、實現GatewayFilter, Ordered
public class MyFilter01 implements GatewayFilter, Ordered {
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); System.out.println("---------------⾃定義過濾器"); return chain.filter(exchange); }
@Override public int getOrder() { return 0; } }2、配置過濾器
@Configuration public class GatewayConfig {
@Bean public RouteLocator routeLocator(RouteLocatorBuilder builder){ System.out.println("-----------------------init"); RouteLocator routeLocator = builder.routes().route( r-> r.path("/product/**") // predicates .filters(f->f.filters( new MyFilter01() )) //filters .uri("http://localhost:8001") //uri ).build(); return routeLocator; }
}
2.2、創建⽹關過濾器 - 繼承AbstractNameValueGatewayFilterFactory
相當於擴展Gateway內置的⽹關過濾器
/** * 創建⼀個類繼承AbstractNameValueGatewayFilterFactory,類名必須以GatewayFilterFactory結尾,類名前⾯的部分即爲當前⾃定義⽹關過濾器的 名字 * 添加@Component註解,註冊到Spring容器 */ @Component public class MyFilterGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory { @Override public GatewayFilter apply(NameValueConfig config) { System.out.println("name:"+config.getName()); System.out.println("value:"+config.getValue()); //創建⾃定義⽹關過濾器並返回 GatewayFilter gatewayFilter = new GatewayFilter() { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~⾃定義⽹關過濾器"); return chain.filter(exchange); } }; return gatewayFilter; } }
spring: application: name: gateway-server cloud: gateway: routes: - id: bbb uri: 'http://localhost:8002' predicates: - Path=/order/** filters: - 'MyFilter=aa,bb'
3、全局過濾器
上述我們講到的過濾器,都是配置在某個路由/服務中,我們稱之爲 ⽹關服務過濾器 ,Gateway提供了內置的全局過濾器,會攔截過濾所有到達⽹關服務器的請求。內置的全局過濾器默認⽣效,⽆需開發者⼲預。根據業務的需求我們也可以⾃定義全局過濾器以實現對所有⽹關請求的攔截和處理。
@Component public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("----------------------------------------------MyGlobalFilter"); List<String> list = exchange.getRequest().getHeaders().get("token"); if (list != null && list.size()>0){ String token = list.get(0); System.out.println("token:"+token); return chain.filter(exchange); } else{ //如果沒有token,或者token過期 ServerHttpResponse response = exchange.getResponse(); //設置響應頭 response.getHeaders().add("ContentType","application/json;charset=utf-8"); //設置狀態碼 response.setStatusCode(HttpStatus.UNAUTHORIZED); // 封裝響應數據 String str = ""; DataBuffer dataBuffer = response.bufferFactory().wrap(str.getBytes()); return response.writeWith(Mono.just(dataBuffer)); } }
@Override public int getOrder() { return 0; } }
八、Gateway動態路由配置
如果在Gateway⽹關的路由配置中,直接將服務的ip port配置進去,將導致:1.如果服務的地址變更,必須要重新配置gateway的路由規則2.如果服務採⽤集羣部署,則不能實現負載均衡
1、Gateway服務器添加eureka-server依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
2、配置⽹關路由
application.ymlserver: port: 9999 spring: application: name: gateway-server main: web-application-type: reactive cloud: gateway: routes: - id: aaa uri: 'lb://api-service1' predicates: - Path=/product/** - id: bbb uri: 'lb://api-service2' predicates: - Path=/order/** eureka: client: service-url: defaultZone: 'http://localhost:8761/eureka'
九、⽹關限流
1、⽹關限流介紹
服務的統⼀訪問使⽤過濾器實現鑑權使⽤⽹關實現限流:通過限制⽤戶的請求進⼊到服務中,有效控制應⽤系統的QPS,達到保護系統的⽬的
2、⽹關限流的常⻅算法
2.1、計數器算法
就是通過記錄在單位時間請求的數量,在這個時間週期內達到設置定值之後就拒絕後續請求的進⼊。缺點:如果⽤戶請求頻率不均勻,有導致短時間、⾼併發的⻛險
2.2、漏桶算法
就是通過控制“漏桶”流出的速率以限制到達服務的⽤戶流量缺點:⽹關會承載⽐較⼤的壓⼒
2.3、令牌桶算法
就是所有進⼊⽹關的請求必須從令牌桶中得到令牌纔可以進⾏服務調⽤,我們可以通過控制令牌桶的容量、令牌的產⽣速率達到控制⽤戶流量的⽬的
3、Gateway⽹關限流
Gateway是基於令牌桶算法,使⽤redis作爲“桶”結合過濾器實現了⽹關限流。
1、添加依賴<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.9.0</version> </dependency>2、配置keyResolver
@Configuration public class AppConfig { @Bean public KeyResolver keyResolver() { //http://localhost:9999/order/query?user=1 //使⽤請求中的user參數的值作爲令牌桶的key //return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); return exchange -> Mono.just(exchange.getRequest().getURI().getPath()); } }3、配置服務的限流規則
server: port: 9999 spring: application: name: gateway-server main: web-application-type: reactive cloud: gateway: routes: - id: aaa uri: 'lb://api-service1' predicates: - Path=/product/** - id: bbb uri: 'lb://api-service2' predicates: - Path=/order/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度 redis-rate-limiter.burstCapacity: 2 #令牌桶容量 redis-rate-limiter.requestedTokens: 1 #每個請求消耗多少個令牌 key-resolver: '#{@keyResolver}' #令牌桶key生成 redis: host: 47.96.11.185 port: 7001 password: qfedu123 database: 0 lettuce: pool: max-active: 10 max-wait: 1000 max-idle: 5 min-idle: 3 eureka: client: service-url: defaultZone: 'http://localhost:8761/eureka'