SpringCloud中使用Zuul實現路由閘道器
轉載:https://www.cnblogs.com/qdhxhz/p/9594521.html
一、什麼是路由閘道器
閘道器是系統的唯一對外的入口,介於客戶端和伺服器端之間的中間層,處理非業務功能 提供路由請求、鑑權、監控、快取、限流等功能。
它將"1對N"問題轉換成了"1對1”問題。
通過服務路由的功能,可以在對外提供服務時,只暴露 閘道器中配置的呼叫地址,而呼叫方就不需要了解後端具體的微服務主機。
二、為什麼要使用微服務閘道器
不同的微服務一般會有不同的網路地址,而客戶端可能需要呼叫多個服務接口才能完成一個業務需求,
若讓客戶端直接與各個微服務通訊,會有以下問題:
- (1)客戶端會多次請求不同微服務,增加了客戶端複雜性
- (2)存在跨域請求,處理相對複雜
- (3)認證複雜,每個服務都需要獨立認證
- (4)難以重構,多個服務可能將會合併成一個或拆分成多個
三、閘道器的優點
微服務閘道器介於服務端與客戶端的中間層,所有外部服務請求都會先經過微服務閘道器客戶只能跟微服務閘道器進行互動,
無需呼叫特定微服務介面,使得開發得到簡化
總的理解閘道器優點
服務閘道器 =路由轉發 + 過濾器
(1)路由轉發:接收一切外界請求,轉發到後端的微服務上去。
(2)過濾器:在服務閘道器中可以完成一系列的橫切功能,
例如許可權校驗、限流以及監控等,這些都可以通過過濾器完成(其實路由轉發也是通過過濾器實現的)。
閘道器: Zuul的使用
1、 建立一個閘道器的服務(建立一個springboot的jar檔案,繼承父專案)
2、新增依賴 eureka-client , config-client(使用配置中心), zuul(閘道器)
<!--新增Eureka-client的依賴 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- zuul閘道器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
3、 在啟動類上添加註解: @EnableEurekaClient , @EnableZuulProxy
@SpringBootApplication @EnableEurekaClient //作為Eureka的client @EnableZuulProxy //進行閘道器代理 public class HouseCloudWebZuulApplication { public static void main(String[] args) { SpringApplication.run(HouseCloudWebZuulApplication.class, args); }
4、新增配置, eureka配置, 路由策略
server:
port:
7777
spring: application: name: houseCloud-webZuul #路由的配置: url包含那些字元, 轉發到哪一個服務 #hello 標識你服務的名字,這裡可以自己定義,一般方便和規範來講還是跟自己服務的名字一樣 zuul: routes: userService: serviceId: house-userService #對應的服務的application.name #服務對映的路徑,通過這路徑就可以從外部訪問你的服務了,目的是為了不爆露你機器的IP,面向服務的路由了,給你選一個可用的出來, #這裡zuul是自動依賴hystrix,ribbon的,不是面向單機 path: /userService/**
#第二個服務 houseService: serviceId: house-houseService path: /houseService/**
#第三個服務。。。
前端頁面訪問:http:localhost:7777/userService/+controller名+引數 (這樣就是訪問house-userService服務下的資料)
zuul作為過濾的使用案例
Zuul 允許開發者在 API 閘道器上通過定義過濾器來實現對請求的攔截與過濾,實現的方法非常簡單。
Filter 的生命週期有 4 個,分別是 “PRE”、“ROUTING”、“POST” 和“ERROR”
禁用過濾器:(在 application.yml 中配置)
#禁用過濾器 zuul.SendResponseFilter.post.disable=true
自定義過濾器:
我們假設有這樣一個場景,因為服務閘道器應對的是外部的所有請求,為了避免產生安全隱患,
我們需要對請求做一定的限制,比如請求中含有 Token 便讓請求繼續往下走,
如果請求不帶 Token 就直接返回並給出提示。
首先自定義一個 Filter,繼承 ZuulFilter 抽象類,在 run() 方法中驗證引數是否含有 Token
@Component //交給spring管理 public class TokenFilter extends ZuulFilter{ //過濾器是否有效 // true: 有效, false: 失效 @Override public boolean shouldFilter() { return true; } /** * 過濾器型別 "PRE”、“ROUTING”、“POST” 和“ERROR” * 閘道器: 路由 * pre: 在路由之前執行 常用 * ROUTING: 正在路由的時候執行 * post: 路由完成之後執行 * error:路由出現錯誤的時候執行 * */ @Override public String filterType() { return "pre"; } //過濾器執行的順序, 非負整數, 越小,越先執行 @Override public int filterOrder() { return 0; } /** * 過濾器邏輯程式碼, 做什麼事情 * 訪問任意東西,都表示放行 * * 攔截:RequestContext 的 setSendZuulResponse(false) 表示攔截 * http:localhost:7777/sd/ds/dd?token=ssss * request.getParamter() * * request --> ServletRequestAttributes得到 * ServletRequestAttributes --> RequestContext(請求上下文) * RequestContext --> RequestContext.getCurrentContext() 獲取當前請求上下文 * */ @Override public Object run() throws ZuulException { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest();//requestContext.getResponse() String token = request.getParameter("token"); if(request.getRequestURI().indexOf("login") > 0) { return null; //返回空表示通過 } if(null == token || token.isEmpty()) {//沒有token requestContext.setSendZuulResponse(false); //requestContext.getResponse().getWriter().print("許可權不足,禁止訪問"); requestContext.getResponse().setContentType("text/html;charset=utf-8"); requestContext.setResponseBody("許可權不足,禁止訪問"); requestContext.setResponseStatusCode(401); //404 資源不存在 405: 提交方式不支援, 400引數繫結錯誤 401/403 許可權不足 return null; } return null; } }
url請求引數如果含有token表示通過執行,如果是login頁面,或者設定註冊頁面是否滿足條件通過
否則返回許可權不足
我們可以根據自己的需要在服務閘道器上定義一些與業務無關的通用邏輯實現對請求的過濾和攔截,比如:簽名校驗、許可權校驗、請求限流等功能