一、Zuul

  • 不同的微服务一般有不同的网络地址,而外部的客户端可能需要调用多个服务的接口才 能完成一个业务需求。比如一个电影购票的手机 APP,可能会调用电影分类微服务,用户微 服务,支付微服务等。如果客户端直接和微服务进行通信,会存在以下问题:
    • 客户端会多次请求不同微服务,增加客户端的复杂性
    • 存在跨域请求,在一定场景下处理相对复杂
    • 认证复杂,每一个服务都需要独立认证
    • 难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务 通信,那么重构会难以实施
    • 某些微服务可能使用了其他协议,直接访问有一定困难

Zuul 包含了对请求的路由和过滤两个最主要的功能:

  • 其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的 基础而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
  • Zuul 和 Eureka 进行整合,将 Zuul 自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获得其他微服务的信息,也即以后的访问微服务都是通过 Zuul 跳转后获得
  • 总体来说,Zuul 提供了代理、路由和过滤的功能


二、代码

1. 创建maven quickstart项目

添加依赖 和 eureka zuul的starter

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.cloud</groupId>
  7. <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
  8. </dependency>

2. application.yaml

spring:
  application:
    name: zuul-server
server:
  port: 9000
eureka:
  client:
    service-url:
      defaultZone: http://localhost:5000/eureka/

3. 主启动类 @EnableZuulProxy

/**
 * @date: 2021/3/7   23:24
 * @author: 易学习
 * @EnableZuulProxy: 开启网关
 */
@EnableZuulProxy
@SpringBootApplication
public class ApplicationZuul {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationZuul.class);
    }
}

4. 访问测试

未命名图片.png

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

zuul工程的 application.yaml 添加配置

zuul:
  routes:
    user:                         # 自定义路由规则的名称,在底层是一个Map的key
      serviceId: consumer-service # 目标微服务名称,ZuulRoute类型的一个属性
      path: /zuul-user/**  # 用来代替目标微服务名称的路径,ZuulRoute类型的一个属性
      # /**表示比配多层路径, 如果没有/**则不能匹配后续的多层路径了

效果:使用微服务和自定义的名称都可以访问
http://localhost:9000/zuul-user/remote/search/user/by/name?keyword=11

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

zuul工程的 application.yaml 添加配置

zuul:
  routes:
    user:                         # 自定义路由规则的名称,在底层是一个Map的key
      serviceId: consumer-service # 目标微服务名称,ZuulRoute类型的一个属性
      path: /zuul-user/**         # 用来代替目标微服务名称的路径,ZuulRoute类型的一个属性
                                  # /**表示比配多层路径, 如果没有/**则不能匹配后续的多层路径了
  #ignored-services:     # 忽略指定微服务名称,让用户不能通过微服务名称访问
   # - consumer-service
  ignored-services: '*'  # 忽略所有微服务名称
  prefix: /yixuexi      # 给访问路径添加统一前缀

未命名图片.png
配置了前缀访问:
http://localhost:9000/yixuexi/zuul-user/remote/search/user/by/name?keyword=11
注意:如果添加了server.servlet.context-path=/myapp 的话 需要先将/myapp打上

五、使用ZuulFilter拦截过滤请求

/**
 * @date: 2021/3/8   16:55
 * @author: 易学习
 */
@Component
public class MyZuulFilter extends ZuulFilter {

    @Override
    public String filterType() {
        // 返回当前过滤器的类型,决定当前过滤器在什么时候执行
        // pre表示在目标微服务之前执行
        // 可选类型包括:pre、route、post、static
        String filterType = "pre";
        return filterType;
    }

    @Override
    public int filterOrder() {
        // 过滤器执行顺序
        return 0;
    }

    /**
     * shouldFilter: 应该过滤, 判断当前请求是否进行过滤
     * 要过滤:返回true,继续执行run方法
     * 不过滤:返回false 直接放行
     * @return
     */
    @Override
    public boolean shouldFilter() {
        // 1.获取当前RequestContext对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        // 2.获取当前请求对象
        HttpServletRequest request = currentContext.getRequest();
        // 3.获取当前请求要访问的目标地址
        String servletPath = request.getServletPath();
        // 4.打印
        System.out.println("servletPath = " + servletPath);
        // 5.当前方法返回值
        // true表示应该过滤,下面继续执行run方法
        // false表示不应该过滤,直接放行
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        // 执行具体过滤逻辑
        System.out.println("run()");
        // 官网文档说,当前实现会忽略这个返回值,所以直接返回null就行
        return null;
    }
}

未命名图片.png