Spring Cloud微服務解決方案⑧:Zuul(API網關)

簡單的來說,我們把zuul這個項目啓動起來,註冊到eurake上,那麼他就可以代理eurake上面的服務(默認),各種玩法聽我細細道來。

源碼下載路徑在:https://download.csdn.net/download/qq_22075041/10869452,代碼參考microservice-gateway-zuul模塊。

首先加入zuul的依賴

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<!--需要eurake的client依賴,因爲要註冊到eurake上-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

啓動類上加一個註解@EnableZuulProxy,配置文件只需要把註冊到eurake的配置做一下就可以了:

server:
  port: 8040
spring:
  application:
    name: microservice-gateway-zuul
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

以上配置zuul默認代理eurake的所有服務,調用的時候以註冊到eurake上的服務名。

但是我覺得服務名太長了不好記,我要自定義,配置如下:

zuul:
  routes:
  # 服務名 訪問路徑  注意/*和/**的區別:適配一層和適配多層
    microservice-provider-user: /user/** 

如果我要忽略某幾個微服務的代理呢?這樣配(多個用逗號分開):

zuul:
  ignored-services: microservice-provider-user,microservice-consumer-movie

如果我只想代理指定的微服務呢?

zuul:
  ignored-services: '*'   # 使用'*'可忽略所有微服務
  routes:
    microservice-provider-user: /user/**

還可以這樣玩:同時指定微服務的serviceId和對應路徑path:

zuul:
  routes:
    abc:                   # 該配置方式中,abc只是給路由一個名稱,可以任意起名。
      service-id: microservice-provider-user
      path: /user/**              # service-id對應的路徑

玩法2:同時指定path和url

zuul:
  routes:
    user-route:                   # 該配置方式中,user-route只是給路由一個名稱,可以任意起名。
      url: http://localhost:8000/ # 指定的url
      path: /user/**              # url對應的路徑。

玩法2升級:同時指定path和URL,並且不破壞Zuul的Hystrix、Ribbon特性

zuul:
  routes:
    user-route:
      path: /user/**
      service-id: microservice-provider-user
ribbon:
  eureka:
    enabled: false    # 禁用掉ribbon的eureka使用。詳見:http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_example_disable_eureka_use_in_ribbon
microservice-provider-user:
  ribbon:
    listOfServers: localhost:8000,localhost:8001

爲Zuul添加全局映射前綴: 應用場景比如項目根目錄不是/ 而是/abc之類的

zuul:
  prefix: /api
  strip-prefix: false # 默認爲ture
  routes:
    microservice-provider-user: /user/**
logging:
  level:
    com.netflix: DEBUG
    
# 訪問Zuul的/api/microservice-provider-user/1路徑,請求將會被轉發到microservice-provider-user的/api/1,,可以查看日誌打印,有助於理解。

爲Zuul添加局部映射前綴,就是給某個服務添加:

zuul:
  routes:
    microservice-provider-user: 
      path: /user/**
      strip-prefix: false
logging:
  level:
    com.netflix: DEBUG
    
# 這樣訪問Zuul的/user/1路徑,請求將會被轉發到microservice-provider-user的/user/1,可以查看日誌打印,有助於理解。

我要忽略某些敏感路徑,這樣配:

zuul:
  ignoredPatterns: /**/admin/**   # 忽略所有包括/admin/的路徑
  routes:
    microservice-provider-user: /user/**

還有基於正則的玩法,削微有點不同,代碼參考microservice-gateway-zuul-reg-exp模塊:

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {

  @Bean
  public PatternServiceRouteMapper serviceRouteMapper() {
    // 調用構造函數PatternServiceRouteMapper(String servicePattern, String routePattern)
    // servicePattern指定微服務的正則
    // routePattern指定路由正則
    return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)", "${version}/${name}");
  }

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

====================================

1.zuul現在使用的是HttpClient,可以使用其他的

2.zuul還支持把一些敏感請求頭文件不傳到代理的服務上

3.zuul服務自身轉發,也可以配置。

4.訪問zuul的/route,可以看到zuul所有代理的情況

5.@EnableZuulServer是一個zuul的輕量級自由註解,不帶有負載,斷路等功能

=========================================

接下里聊一下大文件上傳,參考代碼microservice-gateway-zuul-file-upload模塊:

# 上傳大文件得將超時時間設置長一些,否則會報超時異常。以下幾行超時設置來自http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_uploading_files_through_zuul
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 60000

還有一個小技巧,我們上傳一般使用的是springMVC,當我們使用zuul代理的時候,可以在代理路徑前加上/zuul/*,則不會被springMVC上傳的時候限制大小。

=============================================

zuul的fallback,參考代碼microservice-gateway-zuul-fallback模塊,其實就是自定義一個response

package com.itmuch.cloud.study.fallback;

import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

@Component
public class UserFallbackProvider implements ZuulFallbackProvider {
  @Override
  public String getRoute() {
    // 表明是爲哪個微服務提供回退
    return "microservice-provider-user";
  }

  @Override
  public ClientHttpResponse fallbackResponse() {
    return new ClientHttpResponse() {
      @Override
      public HttpStatus getStatusCode() throws IOException {
        // fallback時的狀態碼
        return HttpStatus.OK;
      }

      @Override
      public int getRawStatusCode() throws IOException {
        // 數字類型的狀態碼,本例返回的其實就是200,詳見HttpStatus
        return this.getStatusCode().value();
      }

      @Override
      public String getStatusText() throws IOException {
        // 狀態文本,本例返回的其實就是OK,詳見HttpStatus
        return this.getStatusCode().getReasonPhrase();
      }

      @Override
      public void close() {
      }

      @Override
      public InputStream getBody() throws IOException {
        // 響應體
        return new ByteArrayInputStream("用戶微服務不可用,請稍後再試。".getBytes());
      }

      @Override
      public HttpHeaders getHeaders() {
        // headers設定
        HttpHeaders headers = new HttpHeaders();
        MediaType mt = new MediaType("application","json", Charset.forName("UTF-8"));
        headers.setContentType(mt);

        return headers;
      }
    };
  }
}

==================================

定義zuul的過濾器:

package com.itmuch.cloud.study.filters.pre;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

public class PreRequestLogFilter extends ZuulFilter {
  private static final Logger LOGGER = LoggerFactory.getLogger(PreRequestLogFilter.class);

  @Override
  public String filterType() {
    return "pre";
  }

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

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

  @Override
  public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
    PreRequestLogFilter.LOGGER.info(String.format("send %s request to %s", request.getMethod(), request.getRequestURL().toString()));
    return null;
  }
}

然後注入這個bean

package com.itmuch.cloud.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

import com.itmuch.cloud.study.filters.pre.PreRequestLogFilter;

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

  @Bean
  public PreRequestLogFilter preRequestLogFilter() {
    return new PreRequestLogFilter();
  }
}

zuul支持自定義Fifter,也有很多實現好的Fifter(在org.springframework.cloud.netflix.zuul.filters包下)。

如果想禁用某一個Fifter,只需設置zuul.<SimpleClassName>.<filterType> .disable = true。例如,要禁用org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter 需設置 zuul.SendResponseFilter.post.disable = true。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章