天天看点

API网关Zuul学习

Zuul的作用

    Zuul是spring cloud中推荐使用的api网关,一般来说,服务是集群部署的,并且不会直接暴露到外网中直接调用,外部客户端想要调用服务无法直接调用服务的实际地址,实际情况也不允许这样做,这时候就需要通过一个称为网关的组件来处理客户端的请求,通过网关来进行分配,zuul的主要功能就是对所有的服务请求进行统一拦截管理,通过负载均衡分发服务请求,与Nginx类似,同时,zuul还可以对服务请求进行监控、日志管理、验签等操作,zuul就像一个守门神,对所有要进城的人进行筛查、登记,然后分配到具体要去的地方。

    总的来说,zuul可以实现反向代理、负载均衡、限流、监控、日志、验签等操作。

Zuul与Nginx的区别

    相同点:可以实现反向代理、负载均衡,都是网关

    区别:

    Zuul:java语言编写,主要适用于微服务框架下的,是在客户端做负载均衡

    Nginx:C语言编写,在服务器端做负载均衡,更适用于对外部的请求进行分发,从功能上来说,Nginx比Zuul更强大,还可以通过一些脚本来扩展功能,Zuul的功能,Nginx也可以实现,但是很麻烦,需要用其他的语言实现。

搭建Zuul网关

1.引入zuul和eureka客户端依赖

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

2.启动类开启zuul,@EnableZuulProxy

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
    public static void main(String[] args){
        SpringApplication.run(ZuulApplication.class,args);
    }

}
           

3.配置路由

#zuul路由配置
zuul:
  routes:
    #路由名称,命名无强制要求
    eureka-client:
      #匹配的请求路径
      path: /eureka-client-zuul/**
      #实际转发的服务别名
      serviceId: eureka-client
    eureka-feign-client:
      path: /eureka-feign-client-zuul/**
      serviceId: eureka-feign-client
           

zuul的原理

    zuul实际上也是一个服务,其核心组件其实是过滤器,zuul的路由转发实际上是通过一层一层不同类型的过滤器实现的,按照顺序主要分为几种:

pre

    pre过滤器可以理解为预处理,是最先经过的过滤器,在请求还没有被转发之前被调用,常用来用来做验签、黑白名单处理,主要做了几个工作:

    1.判断request的涞源

    2.将HttpServletRequest包装成特定对象

    3.将content-type为特定类型的request包装成特定对象

    4.处理debug信息

    5.进行路由规则匹配等预处理操作

route

    route过滤器主要是对请求进行转发,route只会对指定了serviceId的请求进行处理,在route过滤器中将会通过Ribbon以及Hystrix实现负载均衡和限流,是zuul的核心。

    1.匹配path中符合规则的请求路径

    2.根据serviceid从eureka中获取服务地址

    3.通过Ribbon做负载均衡获取具体调用地址

    4.通过httpclient方式进行服务调用

post

    post过滤器是在服务完成调用之后,请求已经处理完,结果返回到客户端之前调用的,无论是在调用过程中成功与否,最终都会通过post过滤器,在这里可以对响应进行处理

error

    error过滤器就是在上面三个过滤器发生异常的时候会触发,但最终还是需要通过post过滤器将响应返回给客户端

关于zuul过滤器的具体实现原理参考:

https://www.jianshu.com/p/ff863d532767

https://www.cnblogs.com/trust-freedom/p/9982680.html

自定义Zuul过滤器实现

    1.继承ZuulFilter

    2.指定过滤器的类型,实现filterType方法(pre、route、post、error)

    3.指定过滤器的顺序,filterOrder方法,默认是0,所有的过滤器都有自己的顺序,包括zuul自己的过滤器,具体顺序可以参考上面贴出的链接,里面有详细解释

    4.设置是否执行过滤器,shouldFilter方法,返回true/false,设置为false的话,过滤器的逻辑便不会被执行

    5.实现过滤器的业务逻辑,run方法,下面是一个例子验证是否请求中是否带有userToken参数,如果没有则不做转发,返回提示。

    6.通过注解@Component将自定义过滤器加入到spring容器当中

@Component
public class TokenFilter extends ZuulFilter {
    @Autowired
    HttpServletRequest request;

    //过滤器的类型
    //pre:可以在请求被路由之前调用
    //routing: 路由请求时被调用
    //post:在routing和error过滤器之后被调用
    //error:处理请求时发生错误时被调用
    @Override
    public String filterType() {
        return "pre";
    }

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

    //过滤器是否要执行
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //过滤器业务逻辑,举例验证是否有userToken参数
    @Override
    public Object run() throws ZuulException {
        String token = request.getParameter("userToken");
        if (StringUtils.isEmpty(token)){
            //获取当前上下文
            RequestContext currentContext = RequestContext.getCurrentContext();
            //设置不转发zuul请求
            currentContext.setSendZuulResponse(false);
            //设置拦截返回的提示
            currentContext.setResponseBody("token is empty");
            //设置状态码
            currentContext.setResponseStatusCode(400);
            return null;
        }
        return null;
    }
}