天天看點

API網關Zuul學習

Zuul的作用

    Zuul是spring cloud中推薦使用的api網關,一般來說,服務是叢集部署的,并且不會直接暴露到外網中直接調用,外部用戶端想要調用服務無法直接調用服務的實際位址,實際情況也不允許這樣做,這時候就需要通過一個稱為網關的元件來處理用戶端的請求,通過網關來進行配置設定,zuul的主要功能就是對所有的服務請求進行統一攔截管理,通過負載均衡分發服務請求,與Nginx類似,同時,zuul還可以對服務請求進行監控、日志管理、驗簽等操作,zuul就像一個守門神,對所有要進城的人進行篩查、登記,然後配置設定到具體要去的地方。

    總的來說,zuul可以實作反向代理、負載均衡、限流、監控、日志、驗簽等操作。

Zuul與Nginx的差別

    相同點:可以實作反向代理、負載均衡,都是網關

    差別:

    Zuul:java語言編寫,主要适用于微服務架構下的,是在用戶端做負載均衡

    Nginx:C語言編寫,在伺服器端做負載均衡,更适用于對外部的請求進行分發,從功能上來說,Nginx比Zuul更強大,還可以通過一些腳本來擴充功能,Zuul的功能,Nginx也可以實作,但是很麻煩,需要用其他的語言實作。

搭建Zuul網關

1.引入zuul和eureka用戶端依賴

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
           

2.啟動類開啟zuul,@EnableZuulProxy

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
    public static void main(String[] args){
        SpringApplication.run(ZuulApplication.class,args);
    }

}
           

3.配置路由

#zuul路由配置
zuul:
  routes:
    #路由名稱,命名無強制要求
    eureka-client:
      #比對的請求路徑
      path: /eureka-client-zuul/**
      #實際轉發的服務别名
      serviceId: eureka-client
    eureka-feign-client:
      path: /eureka-feign-client-zuul/**
      serviceId: eureka-feign-client
           

zuul的原理

    zuul實際上也是一個服務,其核心元件其實是過濾器,zuul的路由轉發實際上是通過一層一層不同類型的過濾器實作的,按照順序主要分為幾種:

pre

    pre過濾器可以了解為預處理,是最先經過的過濾器,在請求還沒有被轉發之前被調用,常用來用來做驗簽、黑白名單處理,主要做了幾個工作:

    1.判斷request的涞源

    2.将HttpServletRequest包裝成特定對象

    3.将content-type為特定類型的request包裝成特定對象

    4.處理debug資訊

    5.進行路由規則比對等預處理操作

route

    route過濾器主要是對請求進行轉發,route隻會對指定了serviceId的請求進行處理,在route過濾器中将會通過Ribbon以及Hystrix實作負載均衡和限流,是zuul的核心。

    1.比對path中符合規則的請求路徑

    2.根據serviceid從eureka中擷取服務位址

    3.通過Ribbon做負載均衡擷取具體調用位址

    4.通過httpclient方式進行服務調用

post

    post過濾器是在服務完成調用之後,請求已經處理完,結果傳回到用戶端之前調用的,無論是在調用過程中成功與否,最終都會通過post過濾器,在這裡可以對響應進行處理

error

    error過濾器就是在上面三個過濾器發生異常的時候會觸發,但最終還是需要通過post過濾器将響應傳回給用戶端

關于zuul過濾器的具體實作原理參考:

https://www.jianshu.com/p/ff863d532767

https://www.cnblogs.com/trust-freedom/p/9982680.html

自定義Zuul過濾器實作

    1.繼承ZuulFilter

    2.指定過濾器的類型,實作filterType方法(pre、route、post、error)

    3.指定過濾器的順序,filterOrder方法,預設是0,所有的過濾器都有自己的順序,包括zuul自己的過濾器,具體順序可以參考上面貼出的連結,裡面有詳細解釋

    4.設定是否執行過濾器,shouldFilter方法,傳回true/false,設定為false的話,過濾器的邏輯便不會被執行

    5.實作過濾器的業務邏輯,run方法,下面是一個例子驗證是否請求中是否帶有userToken參數,如果沒有則不做轉發,傳回提示。

    6.通過注解@Component将自定義過濾器加入到spring容器當中

@Component
public class TokenFilter extends ZuulFilter {
    @Autowired
    HttpServletRequest request;

    //過濾器的類型
    //pre:可以在請求被路由之前調用
    //routing: 路由請求時被調用
    //post:在routing和error過濾器之後被調用
    //error:處理請求時發生錯誤時被調用
    @Override
    public String filterType() {
        return "pre";
    }

    //過濾器的順序
    @Override
    public int filterOrder() {
        return 0;
    }

    //過濾器是否要執行
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //過濾器業務邏輯,舉例驗證是否有userToken參數
    @Override
    public Object run() throws ZuulException {
        String token = request.getParameter("userToken");
        if (StringUtils.isEmpty(token)){
            //擷取目前上下文
            RequestContext currentContext = RequestContext.getCurrentContext();
            //設定不轉發zuul請求
            currentContext.setSendZuulResponse(false);
            //設定攔截傳回的提示
            currentContext.setResponseBody("token is empty");
            //設定狀态碼
            currentContext.setResponseStatusCode(400);
            return null;
        }
        return null;
    }
}