Spring Cloud路由網關和過濾器(zuul)

Java EE 目錄:https://blog.csdn.net/dkbnull/article/details/87932809
Spring Cloud 專欄:https://blog.csdn.net/dkbnull/column/info/36820
Spring Boot 專欄:https://blog.csdn.net/dkbnull/column/info/26341

0. 開發環境

  • IDE:IntelliJ IDEA 2017.1 x64

  • JDK:1.8.0_91

  • Spring Boot:2.0.9.RELEASE

  • Spring Cloud:Finchley.RELEASE

1. Zuul簡介

Zuul是Netflix開源的一個基於JVM路由和服務端的API Gateway服務器,是一個負載均衡器。

Zuul的主要功能是路由轉發和過濾器。路由轉發功能是微服務中很重要的一部分。比如 api/sale/* 接口轉發到sale服務, api/pay/* 接口轉發到pay服務。

Zuul默認整合了Ribbon,實現了負載均衡。

1.1 Zuul功能

  • Authentication:認證
  • Insights:洞察
  • Stress Testing:壓力測試
  • Canary Testing:金絲雀測試
  • Dynamic Routing:動態路由
  • Service Migration:服務遷移
  • Load Shedding:負載均衡
  • Security:安全
  • Static Response handling:靜態響應處理
  • Active/Active traffic management:主動/主動交通管理

2.路由轉發

2.1 新建路由網關服務

新建路由網關服務spring-cloud-zuul

2.2 引入依賴

        <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>

2.3 新建啓動類

@EnableZuulProxy 註解表示開啓Zuul功能。

package cn.wbnull.springcloudzuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class SpringCloudZuulApplication {

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

2.4 新建application.yml

server:
  port: 8091
  servlet:
    context-path: /springcloudzuul

spring:
  application:
    name: spring-cloud-zuul

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8090/springcloudeureka/eureka/

zuul:
  routes:
    zuul-a:
      path: /zuul-a/**
      serviceId: spring-boot-provider
    zuul-b:
      path: /zuul-b/**
      serviceId: spring-boot-provider

2.5 測試

依次啓動spring-cloud-eureka、spring-boot-provider、spring-boot-provider-v2、spring-cloud-zuul

瀏覽器訪問 http://127.0.0.1:8091/springcloudzuul/zuul-a/springbootprovider/gatewayhttp://127.0.0.1:8091/springcloudzuul/zuul-b/springbootprovider/gatewayhello world,this is spring-boot-providerhello world,this is spring-boot-provider-v2 交替返回,路由成功。

  • 127.0.0.1:8091/springcloudzuul 是 spring-cloud-zuul 的訪問地址(ip:port/server.servlet.context-path)

  • zuul-a 和 zuul-b 是我們要路由的地址,根據application.yml配置,這倆地址被路由到 服務id名稱爲 spring-boot-provider 的服務。

  • springbootprovider/gateway 是 spring-boot-provider 服務的接口訪問地址(server.servlet.context-path/接口名),與之前相同,serviceId替換的只是ip:port部分。

2.6 路由配置方式2

也可以使用如下方式配置路由地址

zuul:
  routes:
    zuul-a:
      path: /zuul-a/**
      url: http://localhost:8081/springbootprovider
    zuul-b:
      path: /zuul-b/**
      url: http://localhost:8083/springbootprovider

依次啓動spring-cloud-eureka、spring-boot-provider、spring-boot-provider-v2、spring-cloud-zuul

瀏覽器訪問 http://127.0.0.1:8091/springcloudzuul/zuul-a/gateway ,返回 hello world,this is spring-boot-provider ;瀏覽器訪問 http://127.0.0.1:8091/springcloudzuul/zuul-b/gateway ,返回 hello world,this is spring-boot-provider-v2 ,路由成功。

3. 服務過濾

剛纔我們已經說過,Zuul的主要功能是路由轉發和過濾器,現在我們來介紹下過濾器。

3.1 新建過濾器類

cn.wbnull.springcloudzuul 包下新建 filter 包,再新建 GlobalFilter 類,並 注入到IoC容器中

package cn.wbnull.springcloudzuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class GlobalFilter 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 servletRequest = context.getRequest();
        Object token = servletRequest.getHeader("token");
        if (token == null) {
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(401);
            try {
                context.getResponse().getWriter().write("error: token is null");
            } catch (IOException e) {
            }
        }

        return null;
    }
}
  • filterType():過濾器類型,執行過濾器的時機
    • pre:路由前
    • routing:路由時
    • post:路由後
    • error:發送錯誤時
  • filterOrder():過濾順序
  • shouldFilter():是否需要過濾,可以豐富代碼進行邏輯判斷,true:過濾;false:不過濾。就像上面示例代碼中不進行邏輯判斷直接 return true 表示所有路由都過濾。
  • run():過濾器具體邏輯實現。

3.2 測試

依次啓動spring-cloud-eureka、spring-boot-provider、spring-boot-provider-v2、spring-cloud-zuul,瀏覽器訪問 http://127.0.0.1:8091/springcloudzuul/zuul-a/springbootprovider/gateway ,返回 error: token is null

我們換Postman,Header加上token,再次請求,返回正常,且 hello world,this is spring-boot-providerhello world,this is spring-boot-provider-v2 交替返回,過濾成功。

4. Zuul整合Hystrix

上面我們測試,路由配置的是服務提供者的地址,這樣我們之前配置的負載均衡策略、斷路器就都無法生效了。

下面我們修改路由服務Id名稱,使路由到服務消費者。

4.1 修改spring-boot-consumer-feign-hystrix

修改 spring-boot-consumer-feign-hystrix 服務 application.yml 配置文件

eureka:
  client:
    register-with-eureka: true

其他配置不變。

4.1 修改spring-cloud-zuul

修改 spring-cloud-zuul 服務 application.yml 配置文件

這裏我們不僅要配置zuul路由,還要配置ribbon超時時間,否則可能啓動服務失敗或斷路器不起作用。

ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000

zuul:
  routes:
    zuul-a:
      path: /zuul-a/**
      serviceId: spring-boot-consumer-feign-hystrix

4.2 測試

1、依次啓動 spring-cloud-eureka、spring-boot-provider、spring-boot-provider-v2、spring-boot-consumer-feign-hystrix、spring-cloud-zuul,使用Postman進行測試,測試地址:http://127.0.0.1:8091/springcloudzuul/zuul-a/springbootconsumer/users ,Header加上token,可以看到返回正常,且兩組返回信息交替返回。

{
  "name": "Zuul 測試 name",
  "hello world": "spring-boot-provider"
}
{
  "name": "Zuul 測試 name",
  "hello world": "spring-boot-provider-v2"
}

2、將 spring-boot-provider、spring-boot-provider-v2 服務停止,再次請求,可以看到返回熔斷方法內參數。

{
  "name": "Zuul 測試 name",
  "fallback": "spring-boot-consumer-feign-hystrix by GatewayFallbackFactory",
  "throwable": "feign.RetryableException: Connection refused: connect executing POST http://spring-boot-provider/springbootprovider/users"
}


GitHub:https://github.com/dkbnull/SpringCloudDemo
微信:https://mp.weixin.qq.com/s/lWMudofECNpskWTioI2cIg



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