SpringCloud之Zuul

1.为什么用Zuul

  • 客户端维护大量的ip和port信息,直接访问指定服务
  • 认证和授权操作,需要在每一个模块中都添加认证和授权的操作
  • 项目的迭代,服务要拆分,服务要合并,需要客户端进行大量的变化
  • 统一的把安全性校验都放在Zuul中

在这里插入图片描述

2.Zuul的快速入门

创建Maven项目,修改为Springboot
导入依赖

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

在启动类添加注解

@EnableEurekaClient
@EnableZuulProxy

编写配置文件

# 指定Eureka服务地址
eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka

#指定服务的名称
spring:
  application:
    name: ZUUL

server:
  port: 80

测试

3.Zuul常用配置信息

3.1Zuul的监控界面
导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

编写配置文件

management:
  endpoints:
    web:
      exposure:
        include: "*"

测试

3.2 忽略服务的配置

zuul:
  ignored-services: eureka
  ignored-patterns: /**/search/**

3.3自定义服务配置

# zuul的配置
zuul:
  routes:
    kehu:   # 自定义名称
      path: /aaa/**     # 映射的路径
      serviceId: customer   # 服务名称

3.4 灰度发布

添加一个配置类

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

准备一个服务,提供两个版本

version: v1
#指定服务的名称
spring:
  application:
    name: CUSTOMER-${version}

修改Zuul的配置

# zuul的配置
zuul:
  # 基于服务名忽略服务,无法查看  , 如果需要用到-v的方式,一定要忽略掉
  # ignored-services: "*"

测试

4.Zuul的过滤器执行流程

客户端请求发送到Zuul服务上,首先通过PreFilter链,如果正常放行,会吧请求再次转发给RoutingFilter,请求转发到一个指定的服务,在指定的服务响应一个结果之后,再次走一个PostFilter的过滤器链,最终再将响应信息交给客户端。

5.Zuul过滤器入门

创建POJO类、,继承ZuulFilter抽象类

@Component
public class TestZuulFilter extends ZuulFilter {}

重写方法

@Override  //指定当前过滤器的类型
public String filterType() {
    return FilterConstants.PRE_TYPE;
}

@Override   //指定当前过滤器的执行顺序
public int filterOrder() {
    return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
}

@Override   //配置是否启用
public boolean shouldFilter() {
    // 开启当前过滤器
    return true;
}

@Override
public Object run() throws ZuulException {
    System.out.println("写具体的业务代码");
    return null;
}

测试

6.PreFilter实现token校验

准备访问路径,请求参数的传递token

http://localhost/v2/customer/version?token=123

创建AuthenticationFilter

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

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

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

    @Override
    public Object run() throws ZuulException {
        //..
    }
    
}

在run中写具体的业务逻辑代码

@Override
public Object run() throws ZuulException {
    //1. 获取Request对象
    RequestContext requestContext = RequestContext.getCurrentContext();
    HttpServletRequest request = requestContext.getRequest();

    //2. 获取token参数
    String token = request.getParameter("token");

    //3. 对比token
    if(token == null || !"123".equalsIgnoreCase(token)) {
        //4. token校验失败,直接响应数据
        requestContext.setSendZuulResponse(false);
        requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
    }
    return null;
}

测试

访问路径http://localhost/v2/customer/version?token=123

7.Zuul的降级

创建实体类

@Component
public class ZuulFallBack implements FallbackProvider {}

重写方法

@Override
public String getRoute() {
    return "*";   // 代表指定全部出现问题的服务,都走这个降级方法
}

@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
    System.out.println("降级的服务:" + route);
    cause.printStackTrace();

    return new ClientHttpResponse() {
        @Override
        public HttpStatus getStatusCode() throws IOException {
            // 指定具体的HttpStatus
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }

        @Override
        public int getRawStatusCode() throws IOException {
            // 返回的状态码
            return HttpStatus.INTERNAL_SERVER_ERROR.value();
        }

        @Override
        public String getStatusText() throws IOException {
            // 指定错误信息
            return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
        }

        @Override
        public void close() {

        }

        @Override
        public InputStream getBody() throws IOException {
            // 给用户响应的信息
            String msg = "当前服务:" + route + "出现问题!!!";
            return new ByteArrayInputStream(msg.getBytes());
        }

        @Override
        public HttpHeaders getHeaders() {
            // 指定响应头信息
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            return headers;
        }
    };
}

测试

8.Zuul动态路由

床架一个过滤器,执行顺序最好放在Pre过滤器的最后面
在run中编写业务逻辑代码

@Override
public Object run() throws ZuulException {
    //1. 获取Request对象
    RequestContext context = RequestContext.getCurrentContext();
    HttpServletRequest request = context.getRequest();

    //2. 获取参数,redisKey
    String redisKey = request.getParameter("redisKey");

    //3. 直接判断
    if(redisKey != null && redisKey.equalsIgnoreCase("customer")){
        // http://localhost:8080/customer
        context.put(FilterConstants.SERVICE_ID_KEY,"customer-v1");
        context.put(FilterConstants.REQUEST_URI_KEY,"/customer");
    }else if(redisKey != null && redisKey.equalsIgnoreCase("search")){
        // http://localhost:8081/search/1
        context.put(FilterConstants.SERVICE_ID_KEY,"search");
        context.put(FilterConstants.REQUEST_URI_KEY,"/search/1");
    }

    return null;
}

测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值