微服务网关Zuul详解

简述

  不同的微服务一般会有不同的服务地址,客户端在访问这些地址的时候需要记录几十甚至几百个地址,这对于客户端来说过于复杂和难以维护。

  这样存在的问题有:客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度。而且这样的机制会增加身份认证的难度,每个微服务需要独立认证。

微服务网关

  微服务网关就应运而生,微服务网关介于客户端与服务器之间的中间层它是一个服务器,是系统对外的唯一入口。所有的外部请求都会先经过微服务网关。客户端只需要与网关交互,只知道一个网关地址即可。

Zuul网关

  Zuul网关是是Netflflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用,Zuul组件的核心是一系列的过滤器。这些过滤器可以完成:

  动态路由:动态将请求路由到不同后端集群 

  压力测试:逐渐增加指向集群的流量,以了解性能

  负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求

  静态响应处理:边缘位置进行响应,避免转发到内部集群 

  身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求。Spring Cloud对Zuul进行了整合和增强。 

  zuul的底层基于Servlet,本质上就是一系列的filter过滤器。

zuul的基本使用

  首先要清楚的是zuul是一台服务器,我们要在项目中创建一个新的模组

  引入zuul的相关依赖

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

  在springboot启动类上加入zuul的支持注解

  至此zuul的准备工作已经完成

zuul基础路由配置

  这里对路由的理解就是根据请求URL,将请求分配到对应的处理程序。在微服务体系中,Zuul负责接收所有的请求。根据不同的URL匹配规则,将不同的请求转发到不同的微服务处理。

  我们在项目的yml文件中可以配置zuul的路由:

#路由配置
zuul:
  routes:
    product-server: #路由的id
      path: /product-service/** #配置映射路径
      url: http://127.0.0.1:9001 #映射路径的实际微服务url地址

面向服务的路由配置

  微服务一般是由几十、上百个服务组成,对于一个URL请求,最终会确认一个服务实例进行处理。如果对每个服务实例手动指定一个唯一访问地址,然后根据URL去手动实现请求匹配,这样做显然就不合理。

  Zuul支持与Eureka整合开发,根据ServiceID自动的从注册中心中获取服务地址并转发请求,这样做的好处不仅可以通过单个端点来访问应用的所有服务,而且在添加或移除服务实例的时候不用修改Zuul的路由配置。 

  我们首先要添加eureka的依赖:

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

  然后开启eureka的服务发现:

  我们还需要配置eureka

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
      registry-fetch-interval-seconds: 5 # 获取服务列表的周期:5s
  instance:
    preferIpAddress: true
    ip-address: 127.0.0.1

  此时我们的zuul基础路由配置中的url就可以不用写了,因为此时的服务地址是从eureka中获取的

  我们只需配置serviceId即可

zuul:
  routes:
    product-service: # 这里是路由id,随意写
      path: /product-service/** # 这里是映射路径
      # url: http://127.0.0.1:9001 # 映射路径对应的实际url地址
      serviceId: service-product #整合eureka后会从eureka中获取服务地址
      sensitiveHeaders: #默认zuul会屏蔽cookie,cookie不会传到下游服务,这里设置为空则取 消默认的黑名单,如果设置了具体的头信息则不会传到下游服务

配置的简化

  如果路由的id和service的id一致的话,我们可以只写这么一行配置映射路径

zuul:
  routes:
    #product-service: # 这里是路由id,随意写
    #  path: /product-service/** # 这里是映射路径
    #  # url: http://127.0.0.1:9001 # 映射路径对应的实际url地址
    #  serviceId: service-product #整合eureka后会从eureka中获取服务地址
    #  sensitiveHeaders: #默认zuul会屏蔽cookie,cookie不会传到下游服务,这里设置为空则取 消默认的黑名单,如果设置了具体的头信息则不会传到下游服务
    service-product: /product-service/**

Zuul网关加入之后的架构图

Zuul网关过滤器

  zuul的路由功能实现了统一处理外部请求的功能,负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。

  zuul还提供过滤器功能,负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。

  ZuulFilter有四种类型:

PRE
这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请
求的微服务、记录调试信息等。
ROUTING
这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用
Apache HttpClient或Netfifilx Ribbon请求微服务。 
POST
这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP
Header、收集统计信息和指标、将响应从微服务发送给客户端等。
ERROR
在其他阶段发生错误时执行该过滤器。
  
  我们只需自定义一个filter类并继承ZuulFilter重写四个方法即可定义一个zuul过滤器类
  zuul提供一个RequstContext上下文对象,它内部采用ThreadLocal保存每个请求的一些信息,包括请求路由、错误信息、HttpServletRequest、HttpServletResponse,这使得一些操作是十分可靠的,它还扩展了ConcurrentHashMap,目的是为了在处理过程中保存任何形式的信息
package hjj.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * 自定义的zuul过滤器
 */
@Component
public class LoginFilter extends ZuulFilter {

    //定义过滤器类型 pre routing post error
    @Override
    public String filterType() {
        return "pre";
    }

    //指定过滤器的执行顺序 返回值越小执行顺序越高
    @Override
    public int filterOrder() {
        return 1;
    }

    //当前过滤器是否生效 true使用 false不使用
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //执行过滤器中的业务逻辑 身份认证,所有的请求都需要携带一个参数:access-token
    @Override
    public Object run() throws ZuulException {
        //获取上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        //获取request请求
        HttpServletRequest request = ctx.getRequest();
        //获取request参数
        String token = request.getParameter("access-token");
        //获取token并进行判断
        if(token == null){
            //拦截请求,认证失败
            ctx.setSendZuulResponse(false);//拦截请求
            ctx.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);//返回错误码
        }
        System.out.println("执行了过滤器");
        return null;
    }
}
zuul网关拦截器类 身份验证简单实现
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
一点一点积累,一点一点蜕变!
原文地址:https://www.cnblogs.com/qq2210446939/p/15085687.html