一、概述

上一代zuul 1.x:https://github.com/Netflix/zuul/wiki
關於zuul的鄙人之前博客:SpringCloud全家桶學習之路由網關----Zuul(六),不過看上圖就知道該用誰了,沒錯-----GateWay(其用到了一些新技術如Netty、Spring Web Flux等)更值得我們學習。
二、Gateway
官網地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
Spring Cloud Gateway基於Web Flux框架實現,而Web Flux框架底層則使用了高性能的Reactor模式通信框架Netty。SpringCloud Gateway的目標是提供統一的路由方式且基於Filter鏈的方式提供了網關基本的功能,例如安全、監控/指標,限流等。
1、三大核心概念
(1)Route路由:路由是構建網關的基本模塊,它由ID、目標URI、一系列的斷言和過濾器組成,如果斷言為true則匹配該路由
(2)Predicate斷言:開發人員可以匹配Http請求中的所有內容(例如請求頭、請求參數)如果請求與斷言相匹配則進行路由(參考:Java8:java.util.function.Predicate)
(3)Filter過濾:指的是Spring框架中GatewayFilter的實例,使用過濾器,可以在請求被路由之前或者之后對請求進行修改
2、工作流程

①客戶端向SpringCloud Gateway發出請求,然后在GateWay Handler Mapping中找到與請求相匹配的路由,將其發送到Gateway Web Hander;
②Handler再通過指定的過濾器鏈來將請求發送到我們實際的服務執行業務邏輯,然后返回。過濾器之間用虛線分開是因為過濾器可能在發送代理請求之前(“pre”)或之后(“post”)執行業務邏輯
③Filter在“pre”類型的過濾器中可以做參數校驗、權限校驗、流量監控、日志輸出、協議轉換等;在“post”類型的過濾器中可以做響應內容、響應頭的修改、日志輸出、流量監控等有着非常重要的作用。
核心邏輯:路由轉發+執行過濾器鏈
三、Gateway工程搭建
1、網關路由配置
1、yml配置網關路由
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true # 開啟從注冊中心動態創建路由的功能,利用微服務名稱j進行路由 routes: - id: payment_route # 路由的id,沒有規定規則但要求唯一,建議配合服務名 #匹配后提供服務的路由地址 uri: http://localhost:8001 predicates: - Path=/payment/get/** # 斷言,路徑相匹配的進行路由 #- After=2017-01-20T17:42:47.789-07:00[America/Denver] #- Before=2017-01-20T17:42:47.789-07:00[America/Denver] #- Cookie=username,zzyy #- Header=X-Request-Id, \d+ #請求頭要有X-Request-Id屬性,並且值為正數 #- Host=**.atguigu.com #- Method=GET #- Query=username, \d+ # 要有參數名username並且值還要是正整數才能路由 # 過濾 #filters: # - AddRequestHeader=X-Request-red, blue - id: payment_route2 uri: http://localhost:8001 predicates: Path=/payment/lb/** #斷言,路徑相匹配的進行路由 eureka: instance: hostname: cloud-gateway-service client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

分析:
①添加網關前訪問:http://localhost:8001/payment/get/31
②添加網關后訪問:http://localhost:9527/payment/get/31
2、硬編碼方式注入RouteLocator Bean配置路由
參考官網案例:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
業務需求:通過9527網關訪問到外網的百度新聞網址
@Configuration public class GatewayConfig { /** * 配置了一個id為route-name的路由規則 * 當訪問localhost:9527/guonei的時候,將會轉發至https://news.baidu.com/guonei * * @param routeLocatorBuilder * @return */ @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) { RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); return routes.route("path_route_xd", r -> r.path("/guonei").uri("https://news.baidu.com/guonei")).build(); } @Bean public RouteLocator customRouteLocator2(RouteLocatorBuilder routeLocatorBuilder) { RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); return routes.route("path_route_xd1", r -> r.path("/guoji").uri("https://news.baidu.com/guoji")).build(); } }

分析:上述配置provider方提供均是寫死的,需要改造。
3、微服務名實現動態路由配置
默認情況下,Gateway會根據注冊中心的服務列表,以注冊中心上微服務名為路徑創建動態路由進行轉發,從而實現動態路由的功能。將uri配置為微服務名,並負載均衡
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true # 開啟從注冊中心動態創建路由的功能,利用微服務名稱進行路由 routes: - id: payment_route # 路由的id,沒有規定規則但要求唯一,建議配合服務名 #匹配后提供服務的路由地址 # uri: http://localhost:8001 uri: lb://CLOUD-PAYMENT-SERVICE predicates: - Path=/payment/get/** # 斷言,路徑相匹配的進行路由 #- After=2017-01-20T17:42:47.789-07:00[America/Denver] #- Before=2017-01-20T17:42:47.789-07:00[America/Denver] #- Cookie=username,zzyy #- Header=X-Request-Id, \d+ #請求頭要有X-Request-Id屬性,並且值為正數 #- Host=**.atguigu.com #- Method=GET #- Query=username, \d+ # 要有參數名username並且值還要是正整數才能路由 # 過濾 #filters: # - AddRequestHeader=X-Request-red, blue - id: payment_route2 uri: lb://CLOUD-PAYMENT-SERVICE # uri: http://localhost:8001 predicates: Path=/payment/lb/** #斷言,路徑相匹配的進行路由 eureka: instance: hostname: cloud-gateway-service client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

2、常用Predicates
官網:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories,
可以對路由進行更精細的控制,例如header、cookie等等。

3、自定義Filter
Filter分類:Gateway Fliter(單一31種)、Global Filter(全局--10種)
自定義過濾器類實現GlobalFilter,Orderd接口即可
@Component @Slf4j public class MyLogGatewayFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("come in global filter: {}", new Date()); ServerHttpRequest request = exchange.getRequest(); String uname = request.getQueryParams().getFirst("uname"); if (uname == null) { log.info("用戶名為null,非法用戶"); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } // 放行 return chain.filter(exchange); } /** * 過濾器加載的順序 越小,優先級別越高 * * @return */ @Override public int getOrder() { return 0; } }

