中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

服務網關Spring?Cloud?Zuul的示例分析

發布時間:2022-03-07 11:57:05 來源:億速云 閱讀:122 作者:小新 欄目:開發技術

這篇文章主要為大家展示了“服務網關Spring Cloud Zuul的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“服務網關Spring Cloud Zuul的示例分析”這篇文章吧。

一、Zuul簡介

Zuul作為微服務系統的網關組件,用于構建邊界服務(Edge Service),致力于動態路由、過濾、監控、彈性伸縮和安全。其在微服務架構中有著重要的作用,主要體現在以下六個方面:

Zull、Ribbon以及Eureka相結合可以實現智能路由和負載均衡的功能,Zull可以按照某種策略將請求分發到不同的實例上;

網關作為邊界服務,將內部服務的API接口進行聚合并統一對外暴露接口。保護內部服務的API接口,防止內部服務被外界調用泄露敏感信息;

網關可以對用戶的身份權限進行認證,防止非法請求API接口;

網關可以實現監控功能,實時日志輸出,對請求進行記錄;

網關可以用來實現流量監控,在高流量的情況下,對服務進行降級;

API接口從內部服務分離出來,便于測試

二、請求路由

使用Spring Cloud Zuul實現路由的規則是十分簡單的。路由方式包括兩種:傳統路由方式,面向服務的路由方式。

2.1 傳統路由

下面我們看以下配置:

zuul.routes.holiday.path=/holiday/**
zuul.routes.holiday.url=http://localhosst:8080/

該規則配置表示所有符合/holiday/** 規則的訪問都會被路由轉發到http://localhosst:8080/地址上,例如:當我們訪問http://localhost:5555/holiday/getAllDays,API網關就會將請求轉發到http://localhost:8080/holiday/getAllDays提供的微服務接口上。其中holiday為微服務的名稱,可以任意定義,但是一組path和url映射關系的路由名稱必須相同,下面面向服務的路由方式也是如此。

2.2 面向服務的路由

Spring Cloud Zuul 與 Spring Cloud Eureka 可以實現無縫對接實現面向服務的路由。我們讓路由的path映射到具體的服務上,而具體的url交由Eureka的服務發現機制去自動維護。具體配置如下(其他配置參考下面的實戰):

zuul.routes.holiday.path=/holiday/**
zuul.routes.holiday.service-id=holiday

通過上面的配置,我們不需要維護具體實例的位置,是得維護工作十分簡單。另外,面向服務打的路由默認實現了負載均衡,而傳統路由還需要手動添加所有實例的位置。

三、路由規則

Spring Cloud Zuul提供了默認的路由規則,當然我們也可以修改這個路由規則。

3.1 默認路由規則

Zull與Eureka的配合使用后,Zull會默認配置一個路由規則,這些默認規則的path會使用service-id配置的服務名作為請求的前綴。例如:有holiday服務,他的默認規則如下

zuul.routes.holiday.path=/holiday/**
zuul.routes.holiday.service-id=holiday

由于默認情況下所有Eureka上的服務都會被Zuul自動創建映射關系進行路由,這會使得一些我們不希望對外開放的服務也被外部訪問到。這個時候我們可以配置zuul.ignored-services參數來設置一個服務名匹配表達式進行判斷,如果服務名匹配表達式,那么Zull將跳過這個服務,不為其創建路由規則。例如:zuul.ignored-services=*表示對所有的服務不自動創建路由規則,這樣我們就需要為每個服配置路由規則。

3.2 自定義路由規則

有這樣一個場景,由于業務的擴展,版本的升級,服務存在不同的版本。比如我們有這樣的命名:holiday-v1、holiday-v2,默認情況下,Zuul自動為服務創建的路由表達式會采用服務名做前綴,針對holiday-v1就會產生/holiday-v1,/holiday-v2兩個路徑來做映射,但這樣生成的表達式規則較為單一,不利于路徑規則的管理。

通常,對于上面這種情況,我們希望是生成的路徑為/v1/holiday,/v2/holiday。我們可以通過自定義路由規則來實現,具體代碼如下:

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

PatternServiceRouteMapper對象可以讓開發者通過正則表達式來自定義服務于路由映射的生成關系。

四、Zuul的過濾器

Zull有請求過濾的功能,其過濾器可以在Http請求的發起和響應返回期間執行一系列的過濾器。

Zuul包擴以下四種過濾器:

  • PRE:該類型的filters在Request routing到源web-service之前執行。可以進行一些權限認證,日志記錄,或者額外給Request增加一些屬性供后續的filter使用;

  • ROUTING:該類型的filters用于把Request routing到源web-service,源web-service是實現業務邏輯的服務。這里使用HttpClient請求web-service;

  • POST:該類型的filters在ROUTING返回Response后執行。用來實現對Response結果進行修改,收集統計數據以及把Response傳輸會客戶端;

  • ERROR:上面三個過程中任何一個出現錯誤都交由ERROR類型的filters進行處理。

Zuul過濾器具有以下關鍵特性:

  • Type(類型):Zuul過濾器的類型,這個類型決定過濾器在哪個階段執行,例如:pre,post等階段;

  • Execution Order(執行順序):規定了過濾器的執行順序,Order的值越小,越先執行;

  • Criteria(標準):Filters執行所需條件

  • Action(行動):如果符合執行條件,則執行Action(具體邏輯代碼)

示例如下:

public class MyFilter extends ZuulFilter {
    @Override
    public Object run() {
            RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        System.out.println(String.format("%s AccessUserNameFilter request to %s", request.getMethod(), request.getRequestURL().toString()));
        // 獲取請求的參數
        String username = request.getParameter("username");
        // 如果請求的參數不為空,且值為chhliu時,則通過
        if(null != username && username.equals("chhliu")) {
          // 對該請求進行路由
            ctx.setSendZuulResponse(true);
            ctx.setResponseStatusCode(200);
            // 設值,讓下一個Filter看到上一個Filter的狀態
            ctx.set("isSuccess", true);
            return null;
        }else{
          // 過濾該請求,不對其進行路由
            ctx.setSendZuulResponse(false);
            // 返回錯誤碼
            ctx.setResponseStatusCode(401);
            // 返回錯誤內容
            ctx.setResponseBody("{\"result\":\"username is not correct!\"}");
            ctx.set("isSuccess", false);
            return null;
        }
    }
    @Override
    public boolean shouldFilter() {
    // 是否執行該過濾器,此處為true,說明需要過濾
        return true;
    }
    @Override
    public int filterOrder() {
    // 優先級為0,數字越大,優先級越低
        return 0;
    }
    @Override
    public String filterType() {
    // 前置過濾器
        return "pre";
    }
}

Zuul請求的生命周期如圖所示:

服務網關Spring?Cloud?Zuul的示例分析

五、設置熔斷

通常在服務無法提供服務的時候,需要執行熔斷。zuul上實現熔斷需要實現FallbackProvider的接口。實現接口中的兩個方法:getRoute()用于指定應用在哪個服務上;fallbackResponse()進入熔斷功能的執行邏輯。示例如下:

@Component
public class CustomZuulFallbackHandler implements FallbackProvider {
  private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
  /**
   * 指定處理的service
   *
   * @return
   */
  @Override
  public String getRoute() {
    return "*";
  }
  public ClientHttpResponse fallbackResponse(String route) {
    return new ClientHttpResponse() {
      @Override
      public HttpStatus getStatusCode() throws IOException {
        return HttpStatus.OK;
      }
      @Override
      public int getRawStatusCode() throws IOException {
        return 200;
      }
      @Override
      public String getStatusText() throws IOException {
        return "OK";
      }
      @Override
      public void close() {
      }
      @Override
      public InputStream getBody() throws IOException {
        return new ByteArrayInputStream((route+" is unavailable.").getBytes());
      }
      @Override
      public HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
      }
    };
  }
  @Override
  public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
    if (cause != null) {
      String reason = cause.getMessage();
      logger.info("Excption {}",reason);
    }
    return fallbackResponse(route);
  }
}

六、實戰

6.1 pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.southgis.ibase.parent</groupId>
        <artifactId>parentWebService</artifactId>
        <version>2.0.1-SNAPSHOT</version>
        <relativePath>../../parent/parentWebService/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>api-gateway</artifactId>
    <groupId>com.southgis.ibase.systemassistance</groupId>
    <version>2.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <description>網關服務</description>
    <dependencies>
      <!--服務注冊與發現-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--配置中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <!--cas 客戶端-->
        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>apiGateway</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.southgis.ibase.systemassistance.ApiGatewayCustomApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

6.2 配置文件

bootstrap.properties

#服務名 對應配置文件中的{application}部分
spring.application.name=apiGateway
#對應前配置文件中的{profile}部分
spring.cloud.config.profile=dev2
#配置訪問路徑
server.servlet.context-path=/eureka-server
#注冊中心
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka-server/eureka
#為監控端點 /info和/health端點也加上類似的前綴
management.server.servlet.context-path=/apiGateway
eureka.instance.statusPageUrlPath=${management.server.servlet.context-path}/actuator/info
eureka.instance.healthCheckUrlPath=${management.server.servlet.context-path}/actuator/health
#通過服務連接配置中心
#spring.cloud.config.discovery.enabled=true
#spring.cloud.config.discovery.serviceId=config-server
spring.cloud.config.uri = http://localhost:8080/config-server
#配置文件獲取失敗快速返回
spring.cloud.config.failFast=true
#日志配置
#logging.config=classpath:logback-spring.xml
#logging.path=D:/ibase/logs/holiday
#logging.pattern.console=[%d{yyyy-MM-dd HH:mm:ss}] -- [%-5p]: [%c] -- %m%n
#logging.pattern.file=[%d{yyyy-MM-dd HH:mm:ss}] -- [%-5p]: [%c] -- %m%n

apiGateway-dev2.properties

#訪問端口
server.port=8080
#設置session超時時間為540分鐘
server.servlet.session.timeout=PT540M
#zuul默認為所有服務開啟默認的路由,為了服務安全,此處關閉
zuul.ignored-services=*
#代碼字典服務路由
zuul.routes.codedict.path=/codedict/**
zuul.routes.codedict.service-id=codedict
#是否轉發后還帶轉發特征的字符
zuul.routes.codedict.strip-prefix=false
#行政區劃服務路由
zuul.routes.adminzone.path=/adminzone/**
zuul.routes.adminzone.service-id=adminzone
zuul.routes.adminzone.strip-prefix=false
#是否開啟路由重試
zuul.retryable=true
#對當前服務的重試次數
ribbon.MaxAutoRetries=2
#切換實例的重試次數
ribbon.MaxAutoRetriesNextServer=0
#請求處理的超時時間
ribbon.ReadTimeout=6000
#請求連接的超時時間
ribbon.ConnectTimeout=6000
#對所有操作請求都進行重試
ribbon.OkToRetryOnAllOperations=true
#將 hystrix 的超時時間設置成 5000 毫秒(hystrix超時時間小于ribbon連接超時時間,先走hystrix)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

6.3 過濾器配置

@Configuration
public class ApiGatewayFilter extends ZuulFilter {
  @Override
  public String filterType() {
    return "pre";
  }
  @Override
  public int filterOrder() {
    return 0;
  }
  @Override
  public boolean shouldFilter() {
    return true;
  }
  @Override
  public Object run() throws ZuulException {
    RequestContext context = RequestContext.getCurrentContext();
    HttpServletRequest request = context.getRequest();
    Principal principal = request.getUserPrincipal();
    //獲取用戶的登錄id
    String userId = principal.getName();
    context.addZuulRequestHeader("X-AUTH-ID",userId);
    return null;
  }
}

在這里我們將獲取的登錄用戶id設置到了請求頭中傳遞給內部服務,內部服務可以通過下面的代碼進行獲取:

String user = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("X-AUTH-ID");

6.4 熔斷配置

@Component
public class CustomZuulFallbackHandler implements FallbackProvider {
  private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
  /**
   * 指定處理的service
   *
   * @return
   */
  @Override
  public String getRoute() {
    return "*";
  }
  public ClientHttpResponse fallbackResponse(String route) {
    return new ClientHttpResponse() {
      @Override
      public HttpStatus getStatusCode() throws IOException {
        return HttpStatus.OK;
      }
      @Override
      public int getRawStatusCode() throws IOException {
        return 200;
      }
      @Override
      public String getStatusText() throws IOException {
        return "OK";
      }
      @Override
      public void close() {
      }
      @Override
      public InputStream getBody() throws IOException {
        return new ByteArrayInputStream((route+" is unavailable.").getBytes());
      }
      @Override
      public HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
      }
    };
  }
  @Override
  public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
    if (cause != null) {
      String reason = cause.getMessage();
      logger.info("Excption {}",reason);
    }
    return fallbackResponse(route);
  }
}

6.5 啟動類

**
 * 路由網關服務部署啟動類
 *
 * @author simon
 **/
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableZuulProxy
@EnableEurekaClient
@SpringCloudApplication
public class ApiGatewayMicroApplication {
  public static void main(String[] args) {
    SpringApplication.run(ApiGatewayMicroApplication.class, args);
  }
}

以上是“服務網關Spring Cloud Zuul的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

盐池县| 兴海县| 曲麻莱县| 西青区| 延寿县| 田东县| 榆中县| 莲花县| 综艺| 扶风县| 临桂县| 辉县市| 滦平县| 沙坪坝区| 泰和县| 威宁| 荆州市| 察隅县| 梁山县| 瑞丽市| 万全县| 喀喇沁旗| 湖南省| 遂宁市| 葵青区| 闻喜县| 集贤县| 莲花县| 高邮市| 绥化市| 宣化县| 任丘市| 出国| 夹江县| 固始县| 江门市| 凤台县| 朔州市| 平武县| 远安县| 澜沧|