Spring Cloud 學習紀要七:Zuul

Spring Cloud Zuul:統一網關

  Spring Cloud Zuul 提供動態路由,監控,彈性,安全等邊緣服務,將細粒度的服務組合起來提供一個粗粒度的服務,所有請求都導入一個統一的入口,那麼整個系統只需要暴露一個服務,對外屏蔽服務端實現細節,這樣也減少了客戶端與服務器的網絡調用次數,這就是api gateway,也是Zuul可以幫我們實現的功能。

開發環境 版本
IDEA 2018.2.6
JDK 1.8
Spring Boot 2.0.6
Spring Cloud Finchley.SR2

路由

新建項目zuul

  Maven依賴:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

  配置文件(可以參照前幾章內容將配置放到git倉庫):

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    #    hostname: ZuulName

spring:
  application:
    name: zuul
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config
      profile: dev

  啓動類添加@EnableZuulProxy註解:

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

  在前面幾章的項目均已啓動的前提下,將zuul項目VM options設置-DServer.port=8061,運行成功後訪問http://localhost:8061/provider/hello/chung,發現zuul會自動將請求路由至provider服務。

此路徑中得到provider爲serviceId

自定義路由

  進行如下配置,運行成功後訪問http://localhost:8061/myRoute/hello/chung,zuul也會自動將請求路由至provider服務。

zuul:
  routes:
    provider: /myRoute/**

PRE_TYPE Zuul Filter

  前置過濾器可以實現限流、鑑權、參數校驗等功能。

鑑權、參數校驗

@Component
public class PreFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();

        // 鑑權
        if ("/provider/hello/send".equals(request.getRequestURI())) {
            if (false) {
                currentContext.setSendZuulResponse(false);
                currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
            }
        }

        // 參數校驗
        if (StringUtils.isEmpty(request.getParameter("token"))) {
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
        }
        return null;
    }
}

API限流

  使用令牌桶算法,Google的RateLimiter工具。

@Component
public class RateLimitFilter extends ZuulFilter {
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return SERVLET_DETECTION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        if (!RATE_LIMITER.tryAcquire()) {
            RequestContext currentContext = RequestContext.getCurrentContext();
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(HttpStatus.SC_SERVICE_UNAVAILABLE);
        }
        return null;
    }
}

POST_TYPE Zuul Filter

  後置過濾器可以實現統計、日誌記錄等功能。

@Component
public class PostFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return SEND_RESPONSE_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletResponse response = currentContext.getResponse();
        /**Some Code**/
        response.setHeader("POST_HEADER", UUID.randomUUID().toString());
        return null;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章