服務網關Zuul
學習筆記(2019.11.29完善)
使用服務網關做統一入口和統一認證,他可以和Eureka,Ribbon,Hystrix等組件配合使用。Zuul組件的核心是一系列的過濾器!
配置統一入口
1. 創建模塊SpringBoot_Zuul
並引入依賴:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
2. 創建包與啓動類: 並加上@EnableZuulProxy註解啓用網關
@SpringBootApplication
@EnableZuulProxy
public class ApplicationZuul {
public static void main(String[] args) {
SpringApplication.run(ApplicationZuul.class, args);
}
}
3.創建application.yml
配置文件,並將zuul
模塊註冊上去註冊中心並配置網關相關轉發配置
server:
port: 8080 #指定端口
spring:
application:
name: eureka-zuul #指定服務名
eureka:
client:
serviceUrl: #註冊到註冊中心
defaultZone: http://127.0.0.1:8761/eureka/
instance:
prefer-ip-address: true
zuul:
routes: #轉發配置
springBoot-client: # 名稱可以隨便寫 但最好見名思意
path: /client/** #配置請求URL的請求規則 請求只要是這個地址開頭就去eureka-client模塊找
serviceId: eureka-client #指定Eureka註冊中心中的服務id
tensquare-test: #test模塊
path: /test/** #配置請求URL的請求規則 請求只要是這個地址開頭就去eureka-test模塊找
serviceId: eureka-test #指定Eureka註冊中心中的服務id
..........................
4.啓動測試是否配置好了統一入口,訪問http://localhost:8080/client/getss?id=888888888 看看是否是去eureka-client模塊調用服務
Zuul過濾器 配置統一過濾:
1. 在SpringBoot_Zuul
模塊上創建一個簡單的zuul
過濾器
@Component
public class WebFilter extends ZuulFilter {
@Override
public String filterType() { //過濾器類型
return "pre";// 前置過濾器
}
@Override
public int filterOrder() {
return 0;// 優先級爲0,數字越大,優先級越低
}
@Override
public boolean shouldFilter() {
return true;// 是否執行該過濾器,此處爲true,說明需要過濾
}
@Override
public Object run() throws ZuulException {
System.out.println("zuul過濾器...");
return null;
}
}
filterType
:過濾器的類型,它決定過濾器在請求的哪個生命週期中執行。這裏定義爲pre
,代表會在請求被路由之前執行。參數解釋:pre
: 可以在請求被路由之前調用,route
:在路由請求時候被調用,post
:在route和error過濾器之後被調用,error
:處理請求時發生錯誤時被調用filterOrder
:過濾器的執行順序。當請求在一個階段中存在多個過濾器時,需要根據該方法返回的值來依次執行。shouldFilter
:判斷該過濾器是否需要被執行。這裏我們直接返回了true
,因此該過濾器對所有請求都會生效。實際運用中我們可以利用該函數來指定過濾器的有效範圍。run
:過濾器的具體邏輯。這裏我們通過ctx.setSendZuulResponse(false)
令zuul過濾該請求,不對其進行路由,然後通過ctx.setResponseStatusCode(401)
設置了其返回的錯誤碼,當然我們也可以進一步優化我們的返回,比如,通過ctx.setResponseBody(body)
對返回body內容進行編輯等。
2. 啓動模塊後請求,測試是否經過了過濾器
一般使用於token的校驗: (過濾器實現token校驗)
@Component
public class ManagerFilter extends ZuulFilter {
@Autowired
private JwtUtil jwtUtil;
@Override
public String filterType() {//過濾器類型
return "pre";//前置過濾器
}
@Override
public int filterOrder() {
return 0;//優先級,數字越大,優先級越低
}
@Override
public boolean shouldFilter() {
return true;//過濾器開關,true表示開啓
}
@Override
public Object run() throws ZuulException {
System.out.println("Zuul過濾器");
RequestContext requestContext=RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
if(request.getMethod().equals("OPTIONS")){
return null;
}
//登錄頁面不攔截
String url=request.getRequestURL().toString();
if(url.indexOf("/admin/login")>0){
System.out.println("登陸頁面"+url);
return null;
}
String authHeader =(String)request.getHeader("Authorization");//獲取頭信息
if(authHeader!=null && authHeader.startsWith("Bearer ") ){
String token = authHeader.substring(7);
//使用工具類校驗token是否正確
Claims claims = jwtUtil.parseJWT(token);
if(claims!=null){
if("admin".equals(claims.get("roles"))){
requestContext.addZuulRequestHeader("Authorization",authHeader);
System.out.println("token 驗證通過,添加了頭信息"+authHeader);
return null;
}
}
}
//否則攔截不給經過網關
requestContext.setSendZuulResponse(false);//終止運行
requestContext.setResponseStatusCode(401);//http狀態碼
requestContext.setResponseBody("無權訪問");
requestContext.getResponse().setContentType("text/html;charset=UTF-8");
return null;
}
}
需要注意,這裏我們通過requestContext.setSendZuulResponse(false)
令zuul過濾該請求,不對其進行路由,然後通過requestContext.setResponseStatusCode(401)
設置了其返回的錯誤碼
如果配置了網站前臺的網關就要進行token轉發
我們現在在過濾器中接收header,轉發給微服務
修改過濾器。如果有token,直接轉發。
@Override
public Object run() throws ZuulException {
System.out.println("zuul過濾器...");
//向header中添加鑑權令牌 RequestContexts是zuul包下的類
RequestContext requestContext = RequestContext.getCurrentContext();
//獲取header
HttpServletRequest request = requestContext.getRequest();
String authorization = request.getHeader("Authorization");
if(authorization!=null){
requestContext.addZuulRequestHeader("Authorization",authorization);
}
return null;
}