Spring cloud學習--Zuul01

Zuul解決的問題

  • 做爲系統的統一入口,屏蔽了系統內部各個微服務的細節
  • 能夠與微服務治理框架結合,實現自動化的服務實例維護以及負載均衡的路由轉發
  • 實現接口權限校驗與微服務業務邏輯的解耦

搭建Zuul服務

zuul maven依賴

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

spring-cloud-starter-zuul包含zuul-core、spring-cloud-starter-hystrix、spring-cloud-starter-ribbon、spring-cloud-starter-actratorweb

主類上開啓API網關服務功能

//@SpringCloudApplication = @SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker
@EnableZuulProxy
@SpringCloudApplication
public class ApiGatewayApplication
{
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

配置application.properties

spring.application.name=api-gateway
server.port=5555

實現簡單的傳統路由轉發功能

只須要加入spring

#實現傳統的路由轉發功能
zuul.routes.api-a-url.path=/api-a-url/**
zuul.routes.api-a-url.url=http://localhost:8080/

全部符合/api-a-url/**規則的訪問都將被路由轉發到http://localhost:8080/地址上,也就是說當咱們訪問http://localhost:5555/api-a-url/hello的時候,
API網關服務會將該請求路由到http://localhost:8080/hello提供的微服務上api

面向服務的路由

  • 加入Eureka依賴
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
  • 配置路由
spring.application.name=api-gateway
server.port=5555

#實現傳統的路由轉發功能
#zuul.routes.api-a-url.path=/api-a-url/**
#zuul.routes.api-a-url.url=http://localhost:8080/

zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=eureka-client

zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=feign-consumer

#eureka.instance.hostname=localhost
#註冊服務的註冊中心地址
eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/

注意與傳統路由的區別,一個是面向url的,一個是面向服務的服務器

  • 啓動eureka-server、eureka-client、feign-consumer、api-gateway服務
    訪問http://localhost:5555/api-a/hello、http://localhost:5555/api-b/feign-consumer,能夠訪問http://localhost:2001/hello和http://localhost:9001/hello服務

請求過濾

請求過濾解決的問題

  • 將鑑權校驗的非業務部分剝離出來,造成獨立的業務服務
  • 微服務中不須要調用此業務服務進行鑑權校驗cookie

    簡單的示例

  • 建立過濾器
public class AccessFilter extends ZuulFilter
{
    private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
    //filterType:過濾器的類型,他決定過濾器會在請求的哪一個生命週期中執行,pre表明會在請求被路由以前執行
    @Override
    public String filterType()
    {
        return "pre";
    }
    
    //filterOrder過濾器執行順序
    @Override
    public int filterOrder()
    {
        return 0;
    }
    //shouldFilter執行生效的條件
    @Override
    public boolean shouldFilter()
    {
        return true;
    }
    //過濾器的具體邏輯
    @Override
    public Object run()
    {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());

        Object accessToken = request.getParameter("accessToken");
        if(null == accessToken)
        {
            log.warn("access token is empty.");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            return null;
        }
        log.info("access token ok.");
        return  null;
    }
}
  • 在主類中建立具體的bean,實例化過濾器
@EnableZuulProxy
@SpringCloudApplication
public class ApiGatewayApplication
{
    @Bean
    public AccessFilter accessFilter()
    {
        return  new AccessFilter();
    }

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

訪問http://localhost:5555/api-a/hello?accessToken=token返回hello world,訪問http://localhost:5555/api-a/hello返回401錯誤app

注意細節

  • 簡化path與serviceId組合
    zuul.rotes. = .
    eg:zuul.routes.feign-consumer=/feign-consumer/**
  • zuul默認爲每個服務實例使用其服務名自動建立映射關係進行路由
    例如不配置路由的狀況下,訪問http://localhost:5555/eureka-client/hello?accessToken=token,能夠返回hello world
  • 使用zuul.ignored-services=/user-service/**,能夠跳過該服務,不建立改服務的路由
    例如:zuul.ignored-services=*,對全部服務不自動建立路由

自定義路由映射規則

eg: 想要將名稱userService-v1的服務映射爲/v1/userService/的路由
在主類中加入自定義規則負載均衡

@Bean
    public PatternServiceRouteMapper serviceRouteMapper()
    {
        return new PatternServiceRouteMapper(
                "(?<name>^.+)-(?<version>v.+$)",
                "${version}/${name}"
        );
    }

當匹配表達式的時候,使用此映射規則;不匹配時,採用默認的映射規則框架

路徑匹配

Ant風格

?:匹配任意單個字符
*:匹配任意數量的字符
**:匹配任意數量的字符,支持多級目錄maven

匹配的順序

路由的規則是經過LinkedHashMap保存的,是有序依次加入的,因此是按照配置的前後順序匹配的。可是properties文件是無序的,若是要想按照前後順序匹配,可使用YAML配置文件ide

忽略表達式

使用zuul.ignored-patterns能夠忽略掉API網關對路由的限制,eg:

zuul.ignored-patterns=/**/hello/**

表示任何訪問//hello/的路由都不會獲得映射,得不到返回內容

路由前綴

zuul.prefix=/api

Cookie與頭信息

在請求路由時,zuul會默認過濾掉HTTP請求頭信息中的一些敏感信息,防止他們被傳遞到下游的外部服務器。默認的敏感頭信息經過zuul.sensitiveHeaders參數定義,
包括Cookie、Set-Cookie、Authorization三個屬性

  • 全局爲空覆蓋默認值,不推薦
zuul.sensitiveHeaders=
  • 指定路由參數配置,推薦
#方法1:對指定路由開啓自定義敏感頭
zuul.routes.<router>.customSensitiveHeaders=true
#方法2:將指定路由的敏感頭設置爲空
zuul.routes.<router>.sensitiveHeaders=

重定向的問題

從訪問的路由能夠看出,訪問成功後,http的url仍然是路由跳轉前的web應用實例地址,而不是路由的地址,此問題致使spring security和shiro在登錄完成後,請求頭信息中的狀態碼爲302,請求響應頭信息中的Location指向了具體的服務實例地址,而請求中的host信息缺指向了路由前的host。故網管進行路由轉發前的Host信息沒有設置正確。
解決方法:

zuul.addHostHeader=true

此解決方案適版本而定

Hystrix和Ribbon支持

Zuul天生擁有線程隔離和斷路器的自我保護功能,以及對服務調用的客戶端負載均衡功能。可是使用path與url的映射的路由轉發不會採用HystrixCommand來包裝,不具有線程隔離和斷路器的保護功能,也不具有負載均衡的能力

參數配置

  • API網關路由轉發請求的HystrixCommand執行超時時間的設置,單位爲毫秒
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
  • 設置路由請求轉發,建立請求鏈接的超時時間
ribbon.ConnectTimeout=2000

當此超時時間小於上面的超時時間時,會自動進行重試路由請求
當大於時,不會斷路重連

  • 創建鏈接後的轉發請求時間
ribbon.ReadTimeout=3000

短路重連規則同上

  • 關閉重試機制
#全局關閉
zuul.retryable=false
#指定路由關閉
zuul.routes.<route>.retryable=false
相關文章
相關標籤/搜索