SpringCloud(Greenwich版)Zuul实现微服务网关

推荐以下稳定版本号:

Spring Boot: 2.1.9.RELEASE

Spring Cloud: Greenwich.SR3

一、Zuul简介

  Zuul 是 Netflix 开源的微服务网关组件,Zuul 其实相当于是设备(手机APP)和应用的 Web 网站后端所有请求的前门。它可以和 Eureka、Ribbon、Hystrix 等组件配合使用,支持动态路由与过滤功能。

Zuul 使用了各种不同类型的过滤器,这些过滤器帮助我们执行以下功能:

  • 身份验证与安全性:识别每个资源的身份验证要求,并拒绝那些与要求不符合的请求。

  • 洞察和监控:在边缘跟踪有意义的数据和统计信息,以便为我们提供准确的生产视图。

  • 压力测试:逐渐增加到群集的流量以评估性能。

  • 动态路由:根据需要将请求动态路由到不同的后端群集。

  • 负载分配:为每种类型的请求分配容量,并丢弃超出限制的请求。

  • 静态响应处理:直接在边缘构建一些响应,而不是将其转发到内部集群。

  • 多区域弹性:跨域AWS Region进行请求路由,以便扩大我们的ELB(Elastic Load Balancing)使用范围。

 

二、路由(Router)

1)build.gradle项目依赖

创建gradle模块zuul-service并添加eureka客户端与zuul依赖

dependencies {
    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-eureka-client'

    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-zuul'
}

2)application.yaml配置文件

给当前微服务配置路由,代码如下:

server:
  port: 8080
spring:
  application:
    name: zuul-service
zuul:
  routes:
    provider:
      path: /provider-service/**
      url: http://localhost:8081/
      serviceId: PROVIDER-SERVICE
View Code

zuul.routes下的属性:

  • id:自定义网关路由ID

  • path:动态路由映射路径规则

  • url:映射路径对应的实际微服务地址

  • serviceId:映射到此路由的服务ID

3)启动类ZuulServiceApplication.java

在启动类上添加@EnableZuulProxy注解,标记开启Zuul代理功能。

package org.wesson.springcloud.zuul;

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

@EnableZuulProxy
@SpringBootApplication
public class ZuulServiceApplication {

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

}
View Code

  从@EnableZuulProxy注解源码中能够看出,该注解其实是一个复合注解。包含@EnableCircuitBreaker和@EnableDiscoveryClient两个注解。当启动类添加了@EnableZuulProxy注解时,就自动为该应用增加服务熔断保护功能。同时也将@EnableZuulProxy注解作为一个服务实例注册到服务治理体系中去。所以,启动类不需要再添加这两个注解了。

4)测试

Step1:运行 eureka-server 启动类,端口为8761

Step2:运行 provider-service 启动类,端口为8081

Step3:运行 zuul-service 启动类,端口为8080

Step4:访问http://localhost:8761/,注册到的服务如下图:

Step5:访问http://localhost:8080/provider-service/client/info,可以发现请求路由到了 provider-service 服务上了:

  • hello, service provider port is from:8081

 

三、过滤器(Filter)

1)请求生命周期

Zuul 请求的生命周期如下图,该图详细的描述了各类过滤器的执行顺序:

 

2)token身份验证

  过滤器是 Zuul 的核心组件,它负责应用程序的业务逻辑,并可以执行各种任务。在 Spring Cloud Zuul 中实现的过滤器必须包含4个基本特征:过滤类型 (filterType)、执行顺序 (filterOrder)、执行条件 (shouldFilter)、具体操作 (run)。

以下是几种标准的过滤器类型,它们对应于一个请求的典型生命周期:

  • PRE:转发到微服务之前执行的过滤器。

  • ROUTING:在路由请求时执行的过滤器。

  • POST:在执行微服务获取返回值之后执行的过滤器。

  • ERROR:在整个阶段抛出异常的时候执行的过滤器。

package org.wesson.springcloud.zuul.filter;

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

import javax.servlet.http.HttpServletRequest;

/*
 * CustomZuulFilter:可以实现自定义的过滤器 
 * @Component:交给Spring容器管理,进行组件扫描
 */
@Component
public class CustomZuulFilter extends ZuulFilter {
    /**
     *功能描述:定义过滤器的类型
     * pre
     * routing
     * post
     * error
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     *功能描述:指定过滤器的执行顺序
     * 返回值越小,执行顺序越高
     */
    @Override
    public int filterOrder() {
        return 1;
    }

    /**
     *功能描述:判断当前过滤器是否生效
     * true:将最终调用run()方法
     * false:将不会调用run()方法
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     *功能描述:执行过滤器中的业务逻辑
     */
    @Override
    public Object run() throws ZuulException {
        // 获取Zuul提供的上下文对象RequestContext
        RequestContext ctx = RequestContext.getCurrentContext();
        // 获取request请求
        HttpServletRequest request = ctx.getRequest();
        // 通过request获取参数access-token
        String token = request.getParameter("access-token"); // 所有的请求需要携带一个参数:access-token
        // 判断token是否为空
        if (token == null) {
            // token == null:拦截请求,返回认证失败
            ctx.setSendZuulResponse(false); // 拦截Zuul网关请求
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); // 未经过认证的错误
        }
        // token != null:执行后续操作
        return null;
    }
}
View Code
 
posted @ 2020-03-10 14:35  wessonshin  阅读(331)  评论(0编辑  收藏  举报