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

  1. spring:
  2. application:
  3. name: zuul-server
  4. server:
  5. port: 9000
  6. eureka:
  7. client:
  8. service-url:
  9. defaultZone: http://localhost:5000/eureka/

3. 主启动类 @EnableZuulProxy

  1. /**
  2. * @date: 2021/3/7 23:24
  3. * @author: 易学习
  4. * @EnableZuulProxy: 开启网关
  5. */
  6. @EnableZuulProxy
  7. @SpringBootApplication
  8. public class ApplicationZuul {
  9. public static void main(String[] args) {
  10. SpringApplication.run(ApplicationZuul.class);
  11. }
  12. }

4. 访问测试

未命名图片.png

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

zuul工程的 application.yaml 添加配置

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

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

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

zuul工程的 application.yaml 添加配置

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

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

五、使用ZuulFilter拦截过滤请求

  1. /**
  2. * @date: 2021/3/8 16:55
  3. * @author: 易学习
  4. */
  5. @Component
  6. public class MyZuulFilter extends ZuulFilter {
  7. @Override
  8. public String filterType() {
  9. // 返回当前过滤器的类型,决定当前过滤器在什么时候执行
  10. // pre表示在目标微服务之前执行
  11. // 可选类型包括:pre、route、post、static
  12. String filterType = "pre";
  13. return filterType;
  14. }
  15. @Override
  16. public int filterOrder() {
  17. // 过滤器执行顺序
  18. return 0;
  19. }
  20. /**
  21. * shouldFilter: 应该过滤, 判断当前请求是否进行过滤
  22. * 要过滤:返回true,继续执行run方法
  23. * 不过滤:返回false 直接放行
  24. * @return
  25. */
  26. @Override
  27. public boolean shouldFilter() {
  28. // 1.获取当前RequestContext对象
  29. RequestContext currentContext = RequestContext.getCurrentContext();
  30. // 2.获取当前请求对象
  31. HttpServletRequest request = currentContext.getRequest();
  32. // 3.获取当前请求要访问的目标地址
  33. String servletPath = request.getServletPath();
  34. // 4.打印
  35. System.out.println("servletPath = " + servletPath);
  36. // 5.当前方法返回值
  37. // true表示应该过滤,下面继续执行run方法
  38. // false表示不应该过滤,直接放行
  39. return false;
  40. }
  41. @Override
  42. public Object run() throws ZuulException {
  43. // 执行具体过滤逻辑
  44. System.out.println("run()");
  45. // 官网文档说,当前实现会忽略这个返回值,所以直接返回null就行
  46. return null;
  47. }
  48. }

未命名图片.png