Spring Cloud学习day103:服务网关Zuul

一、服务网关

1.什么是服务网关?

服务网关相当于路由转发加过滤器。
(1)路由转发:接收一切外界请求,转发到后端的微服务上去;
(2)过滤器:在服务网关中可以完成一系列的横切功能,例如权限校验、限流以及监控等,这些都可以通过过滤器完成(其实路由转发也是通过过滤器实现的)。

2.为什么使用网关:

服务网关相当于路由转发加过滤器;由于每个服务引入了这个公共服务,那么相当于在每个服务中都引入了相同的权限校验的代码,使得每个服务的jar包大小无故增加。
由于每个服务都引入了这个公共服务,那么我们后续升级这个服务可能就比较困难,而且公共服务的功能越多,升级就越难,而且假设我们改变了公共服务中的权限校验的方式,想让所有的服务都去使用新的权限校验方式,我们就需要将之前所有的服务都重新引包,编译部署。

3.网关解决了什么问题:

网关的职责:
(1)统一入口:为全部微服务提供唯一入口,网关起到外部和内部的隔离,保障了后台服务的安全性。
(2)鉴权校验:识别每个请求的权限,拒绝不复合要求的请求。
(3)动态路由:动态的将请求路由到不同的后端集群中。
(4)减少客户端与服务的耦合,服务何以独立发展,通过网关层来做映射。

Spring Cloud学习day103:服务网关Zuul_第1张图片
示例

4.创建网关服务简单案例:

  • 创建项目:


    Spring Cloud学习day103:服务网关Zuul_第2张图片
    示例
  • 修改POM文件添加Zuul的启动依赖:
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        
        
            org.springframework.cloud
            spring-cloud-starter-zuul
        
  • 修改配置文件:
spring.application.name=zuul-gateway
server.port=9010

#设置服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
  • 修改启动类添加@EnableZuulProxy注解:
@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}
  • 调用的服务为设计模式中Product-Provider服务:


    Product服务

    Spring Cloud学习day103:服务网关Zuul_第3张图片
    使用服务网关请求服务
  • 使用服务网关访问服务的URL格式:

http://网关服务地址:网关服务端口/访问的服务的名称/访问的服务中的接口的地址;

二、路由器的四种路由规则

(1)使用URL指定路由方式;
(2)使用服务名称指定路由方式;
(3)路由的排除方法;
(4)路由的添加前缀方法;

1.创建项目:

调用的服务还是Product-Provider;配置路由规则主要是修改配置文件;

Spring Cloud学习day103:服务网关Zuul_第4张图片
示例
  • 配置文件:
spring.application.name=zuul-gateway-route
server.port=9011

#设置服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/

2.采用URL指定:

##################### 路由指定:URL 指定  ##################
# URL 匹配关键字,如果包含关键字就跳转到指定的 URL 中  
zuul.routes.e-book-product-provider.path=/aaa/**
zuul.routes.e-book-product-provider.url=http://127.0.0.1:9001/
Spring Cloud学习day103:服务网关Zuul_第5张图片
示例

3.使用服务名称指定:

#################### 路由指定:服务指定 1  ##############
#将路径的/suibian/引到 eureka 的 e-book-product-provider 服务 上 
#规则:zuul.routes.路径名.path ##规则:zuul.routes.路径名.serviceId=eureka 的服务名
zuul.routes.e-book-product-provider.path=/bbb/**
zuul.routes.e-book-product-provider.serviceId=e-book-product-provider
示例
###############路由指定:服务指定 2#############
#zuul.routes 后面跟着的是服务名,服务名后面跟着的是路径规则,这种 配置方式更简单。 
zuul.routes.e-book-product-provider.path=/ccc/**
示例

4.路由排除:

###############路由排除:排除某几个服务##############
#排除后,这个地址将为空 http://127.0.0.1:9030/e-book-product-provider/product/findAll
#多个服务逗号隔开 
zuul.ignored-services=e-book-product-provider
Spring Cloud学习day103:服务网关Zuul_第6张图片
示例
###############路由排除:排除所有服务  ###################
#由于服务太多,不可能手工一个个加,故路由排除所有服务,然后针对要 路由的服务进行手工加
zuul.ignored-services=*
zuul.routes.e-book-order-provider.path=/e-book-order-provider/**
Spring Cloud学习day103:服务网关Zuul_第7张图片
示例
################路由排除:排除指定关键字的路径  ###############
#排除所有包括/finaAll/的路径 
zuul.ignored-patterns=/**/findAll/**
zuul.routes.e-book-order-provider.path=/aaa/**
示例

5.添加前缀:

## http://127.0.0.1:9030/suibian/product-provider/product/findAll 
zuul.prefix=/aaa
zuul.routes.e-book-product-provider.path=/product-provider/ **
Spring Cloud学习day103:服务网关Zuul_第8张图片
示例

三、网关过滤器

1.自定义网关过滤器:

  • 创建项目:


    Spring Cloud学习day103:服务网关Zuul_第9张图片
    示例
  • 修改POM文件:
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        
        
            org.springframework.cloud
            spring-cloud-starter-zuul
        
    
  • 修改配置文件:
spring.application.name=zuul-gateway-filter
server.port=9011

#设置服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
  • 修改启动类:
@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}
  • 创建Filter继承ZuulFilter:
@Component
public class LogFilter extends ZuulFilter {

    private static final Logger logger = LoggerFactory.getLogger(LoggerFactory.class);

    // 是否开启过滤器,默认是false关闭
    @Override
    public boolean shouldFilter() {
        return true;
    }

    // 过滤的内容,在run方法中编写过滤逻辑
    @Override
    public Object run() {
        // 获取请求上下文
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        logger.info("LogFilter....method={},url={}", request.getMethod(), request.getRequestURL().toString());
        return null;
    }

    // 过滤器类型,通过过滤器类型决定了过滤器执行的时间
    @Override
    public String filterType() {
        return "pre";
    }

    // 过滤器的执行顺序:通过整数表示顺序,数值越小,优先级越高
    @Override
    public int filterOrder() {
        return 0;
    }
}
  • 测试:


    示例

2.过滤器的类型:

Zuul的中心是一系列过滤器,能够在HTTP请求和响应的路由过程中执行一系列操作。

方法 作用
FilterType 表示过滤器的类型,使用字符串表示,在Zuul中默认定义了四种不同生命周期的过滤器类型
FilterOrder 使用int值定义过滤器的执行顺序,数值越小优先级越高
ShouldFilter 返回一个boolean类型来判断该过滤器是否执行
run 逻辑处理,两个用途;第一,请求拦截,对请求进行验证判断,如果请求无效就直接断路,如果有效再加工处理;第二,请求结果后处理,对结果做一些加工处理
FilterType类型 作用
Pre 可以在请求被路由之前调用。一般用于身份权限验证、记录调用日志
Routing 在路由请求时候被调用
Post 在route和error过滤器之后被调用。用于信息手机、统计信息
Error 处理请求时发生错误时被调用。用于异常处理封装
  • Zuul请求的生命周期:


    Spring Cloud学习day103:服务网关Zuul_第10张图片
    示例

3.采用网关过滤器实现权限验证:

  • 创建项目:


    Spring Cloud学习day103:服务网关Zuul_第11张图片
    示例
  • 修改POM文件:
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        
        
            org.springframework.cloud
            spring-cloud-starter-zuul
        
    
  • 修改配置文件:
spring.application.name=zuul-gateway-example
server.port=9012

#设置服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
  • 创建Filter继承ZuulFilter:
@Component
public class AccessFilter extends ZuulFilter{
    
    private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class);

    @Override
    public boolean shouldFilter() {
        System.out.println("shouldFilter!!!");
        return true;
    }

    @Override
    public Object run() {
        //获取请求信息
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        logger.info("---------pre---------");
        //获取表单中的token
        String token = request.getParameter("token");
        //判断
        if(token==null) {
            logger.warn("token is null");
            context.setSendZuulResponse(false);//表示请求结束。不在继 续向下请求
            context.setResponseStatusCode(400);//响应的状态码
            context.setResponseBody("{'result':'token is null'}");//响应的内容
            context.getResponse().setContentType("text/html;charset=utf-8");
        }else {
            //访问redis服务进行验证
            logger.info("token not null");
        }
        
        return null;
    }
    @Override
    public String filterType() {
        System.out.println("filterType!!!");
        return "pre";
    }
    @Override
    public int filterOrder() {
        System.out.println("filterOrder!!!");
        return 0;
    }
}
  • 修改启动类:
@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}
  • 测试:


    Spring Cloud学习day103:服务网关Zuul_第12张图片
    示例

    Spring Cloud学习day103:服务网关Zuul_第13张图片
    token为空时

    Spring Cloud学习day103:服务网关Zuul_第14张图片
    token不为空

4.网关过滤器执行的顺序和Post类型:

同一类型的过滤执行顺序和 filterOrder有关。

  • 创建AccessFilter2:
@Component
public class AccessFilter2 extends ZuulFilter {

    private static final Logger logger = LoggerFactory.getLogger(AccessFilter2.class);

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        // 获取请求信息
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        logger.info("---------pre2---------");
        // 添加异常信息
        throw new RuntimeException();
    }
    @Override
    public String filterType() {
        return "pre";
    }
    @Override
    public int filterOrder() {
        return 2;
    }
}
  • 测试:


    Spring Cloud学习day103:服务网关Zuul_第15张图片
    示例
  • 创建Post类型:
@Component
public class PostFilter extends ZuulFilter {

    private static final Logger logger = LoggerFactory.getLogger(PostFilter.class);

    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        // 获取请求信息
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        logger.info("---------Post---------");
        return null;
    }
    @Override
    public String filterType() {
        return "post";
    }
    @Override
    public int filterOrder() {
        return 0;
    }
}
  • 测试:


    Spring Cloud学习day103:服务网关Zuul_第16张图片
    示例

5.使用网关过滤器对系统异常统一处理:

SpringBoot的默认异常处理映射为“/error”。BasicErrorController已经默认实现了“text/html”的处理,如果想返回自定义JSON格式信息,则实现“ErrorController ”接口。

  • 创建ErrorFilter:
@Component
public class ErrorFilter extends ZuulFilter {

    private static final Logger logger = LoggerFactory.getLogger(ErrorFilter.class);

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        // 获取请求信息
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        logger.info("---------Error---------");
        return null;
    }
    @Override
    public String filterType() {
        return "error";
    }
    @Override
    public int filterOrder() {
        return 0;
    }
}
  • 创建ExceptionHandler实现ErrorController接口:
@RestController
public class ExceptionHandler implements ErrorController{

    @Override
    public String getErrorPath() {
        return "/error";
    }
    @RequestMapping("/error")
    public String error() {
        return "{'error':'数据错误'}";
    }
}
  • 测试:


    Spring Cloud学习day103:服务网关Zuul_第17张图片
    示例

    Spring Cloud学习day103:服务网关Zuul_第18张图片
    控制台

Spring Cloud学习day103:服务网关Zuul_第19张图片
页面

四、网关容错

1.Zuul和Hystrix无缝整合:

在 zuul 的 jar 包中包含了 hystrix 的 jar 包。所以我们不需要在项目中添加 Hystrix 的坐标。

  • 访问网关服务的数据监控流:

http://ip:端口号/hystrix.stream;

Spring Cloud学习day103:服务网关Zuul_第20张图片
示例
  • 使用dashboard服务通过可视化的界面监控数据 :


    Spring Cloud学习day103:服务网关Zuul_第21张图片
    示例

2.在网关中实现服务的降级处理:

  • 创建项目:


    Spring Cloud学习day103:服务网关Zuul_第22张图片
    示例
  • 修改POM文件:
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Dalston.SR5
                pom
                import
            
        
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        
        
            org.springframework.cloud
            spring-cloud-starter-zuul
        
    
  • 修改配置文件:
spring.application.name=zuul-gateway
server.port=9011

#设置服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
  • 添加Fallback类实现ZuulFallbackProvider接口:
@Component
public class ProductFallback implements ZuulFallbackProvider {

    // 给定的服务名称,为服务做降级处理
    @Override
    public String getRoute() {
        return "e-book-product-provider";
    }

    // 当服务无法执行时,该方法返回拖地数据
    @Override
    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {

            // 设置响应的头信息
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                MediaType type = new MediaType("application", "json", Charset.forName("utf-8"));
                httpHeaders.setContentType(type);// 设置编码
                return httpHeaders;
            }

            // 设置响应体
            @Override
            public InputStream getBody() throws IOException {
                String content = "Product服务不可用,请联系管理员!";
                return new ByteArrayInputStream(content.getBytes());
            }

            // fallback的状态码,返回的String类型
            @Override
            public String getStatusText() throws IOException {
                return getStatusCode().getReasonPhrase();
            }

            // fallback的状态码,返回的HttpStatus类型
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            // fallback的状态码,返回的int类型
            @Override
            public int getRawStatusCode() throws IOException {
                return getStatusCode().value();
            }

            @Override
            public void close() {

            }
        };
    }
}
  • 修改启动类:
@EnableZuulProxy
@SpringBootApplication
public class ZuulFallBackApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulFallBackApplication.class, args);
    }
}
  • 测试:


    Spring Cloud学习day103:服务网关Zuul_第23张图片
    示例

    Spring Cloud学习day103:服务网关Zuul_第24张图片
    降级

3.在高并发情况下,网关实现限流达到自我保护:

在规定时间内限制对服务端的请求次数,如果超过限制次数服务端会抛出异常,从而实现限流的效果;主要通过修改配置文件中的配置信息实现。

  • 修改POM文件,添加zuul-ratelimit坐标:
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Dalston.SR5
                pom
                import
            
        
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        
        
            org.springframework.cloud
            spring-cloud-starter-zuul
        
        
            com.marcosbarbero.cloud
            spring-cloud-zuul-ratelimit
            1.3.4.RELEASE
        
    
  • 添加配置信息:
spring.application.name=zuul-gateway-ratelimt
server.port=9012

#设置服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/

#路由规则
zuul.routes.e-book-product-provider.path=/product/**
zuul.routes.e-book-product-provider.serviceId=e-book-product-provider
#路由规则
zuul.routes.e-book-order-provider.path=/order/**
zuul.routes.e-book-order-provider.serviceId=e-book-order-provider
  • 修改启动类:
@EnableZuulProxy
@SpringBootApplication
public class ZuulFallBackApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulFallBackApplication.class, args);
    }
}
  • 实现全局限流修改配置文件:
#全局配置限流
zuul.ratelimit.enabled=true
#60s 内请求超过 3 次,服务端就抛出异常,60s 后可以恢复正常请求
zuul.ratelimit.default-policy.limit=3
zuul.ratelimit.default-policy.refresh-interval=60
#针对 IP 进行限流,不影响其他 IP
zuul.ratelimit.default-policy.type=origin
  • 测试:


    Spring Cloud学习day103:服务网关Zuul_第25张图片
    正常数据
Spring Cloud学习day103:服务网关Zuul_第26张图片
示例
  • 实现局部限流,修改配置文件:
#局部限流:针对某个服务进行限流 
##开启限流
zuul.ratelimit.enabled=true
##60s 内请求超过 3 次,服务端就抛出异常,60s 后可以恢复正常请求 
zuul.ratelimit.policies.e-book-product-provider.limit=3
zuul.ratelimit.policies.e-book-product-provider.refresh-int erval=60
##针对某个 IP 进行限流,不影响其他 IP
zuul.ratelimit.policies.e-book-product-provider.type=origin
Spring Cloud学习day103:服务网关Zuul_第27张图片
product服务

Spring Cloud学习day103:服务网关Zuul_第28张图片
order服务
  • 网关限流参数:


    Spring Cloud学习day103:服务网关Zuul_第29张图片
    示例

4.Zuul性能调优,网关的两层超时调优:

主要是对Hystrix和Ribbon超时问题造成请求连接超时;设置两层超时调优Ribbon的超时时间必须要小于Hystrix的超时时间。

Spring Cloud学习day103:服务网关Zuul_第30张图片
示例
  • 创建项目:


    Spring Cloud学习day103:服务网关Zuul_第31张图片
    示例
  • 修改POM文件,添加Zuul依赖:

    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Dalston.SR5
                pom
                import
            
        
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        
        
            org.springframework.cloud
            spring-cloud-starter-zuul
        
    
  • 修改配置文件:
spring.application.name=zuul-gateway
server.port=9014

#设置服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/

#第一层 hystrix 超时时间设置 
#默认情况下是线程池隔离,超时时间 1000ms 
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=8000
 
#第二层 ribbon超时时间设置:设置比第一层小 
#请求连接的超时时间: 默认 5s 
ribbon.ConnectTimeout=5000
# 请求处理的超时时间: 默认 5s
ribbon.ReadTimeout=5000
  • 修改启动类:
@EnableZuulProxy
@SpringBootApplication
public class ZuulTimeoutApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulTimeoutApplication.class, args);
    }
}
  • 将服务的线程睡两秒模拟服务超时:
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
  • 测试:


    Spring Cloud学习day103:服务网关Zuul_第32张图片
    示例

你可能感兴趣的:(Spring Cloud学习day103:服务网关Zuul)