Spring Cloud之API网关(Zuul)

目录

Zuul

简介

功能

工作流程

搭建

1.引入依赖

2.添加注解

3.路由转发

4.测试

实现原理

@EnableZuulProxy注解

ZuulServlet

FilterProcessor

Zuul内置过滤器

常用配置


Zuul

简介

        zuul是SpringCloud子项目的核心组件之一,可以作为微服务架构中的API网关使用,支持动态路由和过滤功能;

功能

1.统一入口:为全部服务提供一个唯一的入口,网关起到了外部和内部的隔离作用

2.鉴权校验:识别每一个请求的权限,拒绝不符合要求的请求

3.动态路由:动态的将请求路由到不同的后端集群中

4.减少客户端与服务器端的耦合:服务可以独立发展,通过网关来进行映射

工作流程

Zuul本质是一个Servlet来对请求进行控制,核心是创建了一系列的过滤器。Zuul包括以下四种过滤器:       

        1、PRE过滤器:请求路由到具体的服务之前执行,可以用作安全校验、身份校验、参数校验等前置工作;

        2、ROUTING过滤器:用于将请求路由到具体的服务实例,默认使用Http Client进行网络请求;

        3、POST过滤器:在请求已经被路由到微服务后执行,通常用于收集统计信息、指标并将响应返回给客户端;

        4、ERROR过滤器:在其他过滤器出现异常时执行;

各个类型的过滤器执行顺序依次为PRE过滤器->ROUTING过滤器->POST过滤器,如果出现异常就执行ERROR过滤器

搭建

1.引入依赖

        <dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
	
		<!-- zuul 依赖 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>

2.添加注解

启动类添加注解 @EnableZuulProxy

@SpringBootApplication
 @EnableZuulProxy        //开启Zuul
 @EnableEurekaClient
 public class ZuulMain9401 {
     public static void main(String[] args) {
         SpringApplication.run(ZuulMain9401.class, args);
     }
 }

        因为不涉及服务消费等,只是做api的处理,所以主启动类还是比较简单的

3.路由转发

1.在原有的application.yml配置文件上添加:

 zuul:
   routes:
     user-a:
       path: /api-a/**
       serviceId: eureka-provide

user-a:随便定义

path:外部访问路径

serviceId:微服务配置文件的spring.application.name 的值

2.设置url

 zuul:
   routes:
 #    user-a:
 #      path: /api-a/**
 #      serviceId: eureka-provide
     user-b:
       path: /api-b/**
       url: http://localhost:7101/

url:需要转发到哪个服务

3.设置非注册Eureka的服务id

        通过Ribbon设置访问一些没有注册进Eureka的服务,同样在API网关也能通过配置文件设置Ribbon来达到一样的效果

 zuul:
   routes:
 #    user-a:
 #      path: /api-a/**
 #      serviceId: eureka-provide
 #    user-b:
 #      path: /api-b/**
 #      url: http://localhost:7101/
     user-c:
       path: /api-c/**
       serviceId: provide-without-eureka
 ​
 #一定需要这个才行
 ribbon:
   eureka:
     enabled: false
 provide-without-eureka:
   ribbon:
     ServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
     listOfServers: localhost:7201, localhost:7202
     ConnectTimeout: 1000
     ReadTimeout: 3000
     MaxTotalHttpConnections: 500
     MaxConnectionsPerHost: 100

serviceId同样是微服务的名称,然后对这个微服务设置,所以是设置微服务名[provid-without-eureka].ribbon

4.测试

接着访问http://localhost:8080/api-a/eureka/provide,按照分析,应该会被转发到eureka-provide 服务里的eureka/provide路径。

实现原理

@EnableZuulProxy注解

        zuul的使用比较简单,只需要在启动类上添加@EnableZuulProxy注解即可,zuul所有的功能都是围绕改注解进行,@EnableZuulProxy的作用是加载ZuulProxyMarkerConfiguration的实例:

@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {

}

ZuulProxyMarkerConfiguration的作用是注入一个ZuulProxy的标记实例

@Configuration
public class ZuulProxyMarkerConfiguration {
    @Bean
    public Marker zuulProxyMarkerBean() {
        return new Marker();
    }

    class Marker {
    }
}

内部类Marker唯一的作用就是用于标记,所以需要看哪里需要用到该标记,通过引用搜索发现引用的地方是ZuulProxyAutoConfiguration,父类是ZuulServerAutoConfiguration

@Configuration
@EnableConfigurationProperties({ ZuulProperties.class })
@ConditionalOnClass(ZuulServlet.class)
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)
// Make sure to get the ServerProperties from the same place as a normal web app would
// FIXME @Import(ServerPropertiesAutoConfiguration.class)
public class ZuulServerAutoConfiguration {

父类ZuulServerAutoConfiguration中会向Spring容器中注入ServletRegistrationBean实例,该实例中创建了一个ZuulServlet。而Zuul的核心功能就在于这个ZuulServlet,Zuul接收到的所有请求最终都会由于ZuulServlet的service方法来完成

@Bean
    @ConditionalOnMissingBean(name = "zuulServlet")
    public ServletRegistrationBean zuulServlet() {
        ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean<>(new ZuulServlet(),
                this.zuulProperties.getServletPattern());
        // The whole point of exposing this servlet is to provide a route that doesn't
        // buffer requests.
        servlet.addInitParameter("buffer-requests", "false");
        return servlet;
    }

ZuulServlet

ZuulServlet继承之HttpServlet,初始化init方法创建了ZuulRunner对象,而核心功能在于service方法,所有请求都会先执行到service方法

@Override
    public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
        try {
            /** 1.初始化ZuulRunner 对象*/
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
            /** 2.获取HttpRequest请求上下文*/
            RequestContext context = RequestContext.getCurrentContext();
            context.setZuulEngineRan();

            try {
                /** 3.执行pre过滤器*/
                preRoute();
            } catch (ZuulException e) {
                /** 异常时执行error过滤器和post过滤器*/
                error(e);
                postRoute();
                return;
            }
            try {
                /** 4.执行route过滤器*/
                route();
            } catch (ZuulException e) {
                /** 异常时执行error过滤器和post过滤器*/
                error(e);
                postRoute();
                return;
            }
            try {
                /** 5.执行post过滤器*/
                postRoute();
            } catch (ZuulException e) {
                /** 异常时执行error过滤器*/
                error(e);
                return;
            }

        } catch (Throwable e) {
            error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
        } finally {
            /** 清理本地缓存RequestContext*/
            RequestContext.getCurrentContext().unset();
        }
    }

FilterProcessor

        FilterProcessor是过滤器的具体执行者,是一个单例对象。ZuulServlet的各种过滤器最终分别执行了FilterProcessor的preRoute()、route()、postRoute()、error()方法,而这四个方法最终都是执行了FilterProcessor的内部方法runFilters(String filterType)方法。

public Object runFilters(String sType) throws Throwable {
        if (RequestContext.getCurrentContext().debugRouting()) {
            Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
        }
        boolean bResult = false;
        /** 1.获取指定类型的过滤器列表*/
        List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                ZuulFilter zuulFilter = list.get(i);
                /** 2.遍历执行过滤器*/
                Object result = processZuulFilter(zuulFilter);
                if (result != null && result instanceof Boolean) {
                    bResult |= ((Boolean) result);
                }
            }
        }
        return bResult;
    }

Zuul内置过滤器

        Zuul过滤器可以通过自定义ZuulFilter实现类来添加,同时Zuul还提供了内置的众多过滤器,分别如下图示,比较核心的就是RibbonRoutingFilter,这个过滤器负载路由转发并且集成了Ribbon的负载均衡功能:

        Zuul本质上就是一个Servlet,并且通过Spring容器管理了一系列的过滤器ZuulFilter实例,各个ZuulFilter有一个类型,包括preRoute、route、postRoute、error四种类型,不同的类型执行的顺序和时机不同。当请求进入Zuul时,由ZuulServlet接收并通过service方法处理。service方法逻辑就是从Spring容器中找到各种类型的ZuulFilter过滤器实例,然后遍历按顺序和时机来执行过滤器的处理逻辑。使用时可以自定义ZuulFilter来对请求的不同时间短进行功能扩展。

常用配置

zuul:
  #给服务配置路由
  routes:
    user-service:
      path: /userService/**
    feign-service:
      path: /feignService/**
  #关闭默认路由配置
  ignored-services: user-service,feign-service
  #给网关路由添加前缀
  prefix: /proxy
  #配置过滤敏感的请求头信息,设置为空就不会过滤
  sensitive-headers: Cookie,Set-Cookie,Authorization
  #设置为true重定向是会添加host请求头
  add-host-header: true
  # 关闭重试机制
  retryable: true
  PreLogFilter:
    pre:
      #控制是否启用过滤器
      disable: false

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值