一、什么是Zuul

Zuul 包含了对请求的路由过滤两个主要的功能:
路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础;
过滤功能负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。

Zuul 和 Eureka 进行整合,将 Zuul 自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取其他微服务的信息,同时以后的访问微服务都是通过 Zuul 跳转后获得。
Zuul统一入口

二、代码实现

这里的前提是:已经创建好了 parent父工程,common 工程,provider 工程、consumer 工程、Eureka 工程。

1、创建一个 Zuul 工程
pro07-spring-cloud-zuul

2、在 Zuul 工程 的 pom.xml 中加入依赖

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

3、创建 application.yml 配置文件

server:
  port: 9000

spring:
  application:
    name: zuul-gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:5000/eureka/

4、创建主启动类 SpringCloudZuul
加上 @EnableZuulProxy 注解 启用 Zuul 网关代理功能

// 启用 Zuul 网关代理功能
@EnableZuulProxy
@SpringBootApplication
public class SpringCloudZuul {

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

5、依次启动 Eureka注册中心、provider、consumer、Zuul ,进行访问测试

① 初步访问
初步访问地址分析

初步访问

三、配置路由原则

① 使用指定地址代替微服务名称

zuul:
  routes:
    employee:                                       # 自定义路由规则的名称,在底层的数据结构中是 Map 的键
      service-id: com-feign-consumer                      # 目标微服务名称,ZuulRoute 类型的一个属性
      path: /zuul-emp/**                            # 用来代替目标微服务名称的路径, ZuulRoute 类型的一个属性
                                                    # /**表示匹配多层路径

效果:使用微服务名称和新配置的地址都可以访问

使用微服务名称访问:
初步访问

使用新配置的地址访问:
通过新配置的地址访问

② 让用户不能通过微服务名称访问

zuul:
  routes:
    employee:                                       # 自定义路由规则的名称,在底层的数据结构中是 Map 的键
      service-id: com-feign-consumer                      # 目标微服务名称,ZuulRoute 类型的一个属性
      path: /zuul-emp/**                            # 用来代替目标微服务名称的路径, ZuulRoute 类型的一个属性
                                                    # /**表示匹配多层路径

  ignored-services:                                 # 忽略指定微服务名称,让用户不能通过微服务名称访问
    - com-feign-consumer

效果:只能通过新配置的地址访问

使用微服务名称访问:
使用微服务名称访问

使用新配置的地址访问:
使用新配置的地址访问

③忽略所有微服务名称

zuul:
  routes:
    employee:                                       # 自定义路由规则的名称,在底层的数据结构中是 Map 的键
      service-id: com-feign-consumer                      # 目标微服务名称,ZuulRoute 类型的一个属性
      path: /zuul-emp/**                            # 用来代替目标微服务名称的路径, ZuulRoute 类型的一个属性
                                                    # /**表示匹配多层路径

#  ignored-services:                                 # 忽略指定微服务名称,让用户不能通过微服务名称访问
#    - com-feign-consumer

  ignored-services: '*'                             # 忽略所有微服务名称

④给访问路径添加统一前缀

zuul:
  routes:
    employee:                                       # 自定义路由规则的名称,在底层的数据结构中是 Map 的键
      service-id: com-feign-consumer                      # 目标微服务名称,ZuulRoute 类型的一个属性
      path: /zuul-emp/**                            # 用来代替目标微服务名称的路径, ZuulRoute 类型的一个属性
                                                    # /**表示匹配多层路径

  ignored-services: '*'                             # 忽略所有微服务名称
  
#  ignored-services:                                 # 忽略指定微服务名称,让用户不能通过微服务名称访问
#    - com-feign-consumer

  prefix: /consumer                                 # 给访问路径添加统一前缀

效果:只有在新配置的地址前加上前缀才能访问

没有加前缀访问:
未加前缀访问

加前缀后访问:
加前缀后访问

四、使用ZuulFilter拦截过滤请求

1、需要编写一个类继承 ZuulFilter 类,并实现里面的方法。

/**
 *
 * 使用 ZuulFilter 拦截过滤请求
 *
 * @author: Herz
 * @date: 2021/7/26 21:17
 */
@Component
public class MyZuulFilter extends ZuulFilter {

    private static final Logger logger =  LoggerFactory.getLogger(MyZuulFilter.class);

    @Override
    public String filterType() {

        // 返回当前过滤器类型
        // 可选类型包括:pre、route、post、static
        // 如果需要在目标微服务前面执行过滤操作,选用 pre 类型
        String fileType = "pre";

        return fileType;
    }

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

    /**
     * 判断当前请求会否要进行过滤
     * @return true:表示要过滤,继续执行 run()方法
     *         false:表示不过滤,直接放行
     */
    @Override
    public boolean shouldFilter() {
        // 获取 requestContext 对象
        RequestContext requestContext = RequestContext.getCurrentContext();

        // 获取 当前请求 对象
        HttpServletRequest request = requestContext.getRequest();

        // 判断当前请求参数是否为 signal=hello
        String parameter = request.getParameter("signal");

        return "hello".equals(parameter);
    }

    @Override
    public Object run() throws ZuulException {

        logger.info("当前请求要进行过滤,run()执行了");

        // 官方文档说:当前实现会忽略这个返回值,所以返回 null 即可
        return null;
    }
}

2、发送请求访问

① 当请求参数 signal 不满足过滤条件时
不满足过滤条件,不执行run()
控制台没有打印信息。

②当请求参数 signal 满足过滤条件时(即 signal=hello)
满足过滤条件,执行run()
同时,控制台也打印了信息
控制台打印信息

最后修改:2021 年 07 月 26 日 09 : 38 PM
如果觉得我的文章对你有用,请随意赞赏