springcloud-zuul进阶篇

Posted 知识追寻者[同公众号]

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springcloud-zuul进阶篇相关的知识,希望对你有一定的参考价值。

一 前言

经过zuul初级篇(博客或者公主号springcloud专栏可以找到)的学习,读者都懂得如何简单的使用zuul进行路由网关配置,在进阶篇中你将获得zuul核心功能过滤器的基本使用,通过zuul实现文件上传等;

二管理端点

默认情况下使用@EnableZuulProxy注解和 Spring Boot Actuator集成方式会有两个端点 RoutesFilters

2.1 zuul-server

在zuul-server中添加依赖actuator

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在 application.yml中添加配置如下,开启routes端点

management:
  endpoints:
    web:
      exposure:
        include: routes,filters

启动 eureka-server, zuul-server;

2.2 ruotes端点

访问地址http://localhost:8100/actuator/routes 可以查看如下结果,表明集成成功;

{
/api/**: "zuul-client",
/eureka-server-cluster/**: "eureka-server-cluster",
/zuul-client/**: "zuul-client"
}

还可以详细的查看routes 端点具体的内容;访问地址 http://localhost:8100/actuator/routes/details 可以查看到如下内容;

{
    "/api/**": {
        "id": "zuul-client",
        "fullPath": "/api/**",
        "location": "zuul-client",
        "path": "/**",
        "prefix": "/api",
        "retryable": false,
        "customSensitiveHeaders": false,
        "prefixStripped": true
    },
    "/eureka-server-cluster/**": {
        "id": "eureka-server-cluster",
        "fullPath": "/eureka-server-cluster/**",
        "location": "eureka-server-cluster",
        "path": "/**",
        "prefix": "/eureka-server-cluster",
        "retryable": false,
        "customSensitiveHeaders": false,
        "prefixStripped": true
    },
    "/zuul-client/**": {
        "id": "zuul-client",
        "fullPath": "/zuul-client/**",
        "location": "zuul-client",
        "path": "/**",
        "prefix": "/zuul-client",
        "retryable": false,
        "customSensitiveHeaders": false,
        "prefixStripped": true
    }
}

2.3 filter端点

访问地址http://localhost:8100/actuator/filters 可以的到具体过滤器信息如下;每个过滤器模块中具体包含哪些具体过滤器请读者看返回结果;

  1. error 过滤器
  2. post 过滤器
  3. pre 过滤器
  4. route 过滤器
{
    "error": [{
        "class": "org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter",
        "order": 0,
        "disabled": false,
        "static": true
    }],
    "post": [{
        "class": "org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter",
        "order": 1000,
        "disabled": false,
        "static": true
    }],
    "pre": [{
        "class": "org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter",
        "order": 1,
        "disabled": false,
        "static": true
    }, {
        "class": "org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter",
        "order": -1,
        "disabled": false,
        "static": true
    }, {
        "class": "org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter",
        "order": -2,
        "disabled": false,
        "static": true
    }, {
        "class": "org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter",
        "order": -3,
        "disabled": false,
        "static": true
    }, {
        "class": "org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter",
        "order": 5,
        "disabled": false,
        "static": true
    }],
    "route": [{
        "class": "org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter",
        "order": 100,
        "disabled": false,
        "static": true
    }, {
        "class": "org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter",
        "order": 10,
        "disabled": false,
        "static": true
    }, {
        "class": "org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter",
        "order": 500,
        "disabled": false,
        "static": true
    }]
}

三 过滤器

3.1 过滤器特征

在zuul的request和response工作过程的核心就是以过滤器为基础执行一系列的动作;zuul的核心特色如下

  1. Type : 过滤器类型定义了在路由期间过滤器被执行的顺序;
  2. Execution Order: 同一类型的过滤器中,能够定义多个过滤器的执行顺序;
  3. Criteria: 过滤器被执行的条件;
  4. Action: 过滤条件满足情况下,被执行的动作;

zuul 提供了一个框架去动态的读取,编译,和运行过滤器;过滤器之间的交流机制是通过RequestContext 进行分享各自的状态;RequestContext 中有各自独立的request (request 由 ThreadLocal 持有) 进行 存储数据;每个ThreadLocal 都会负责各自请求信息,错误信息,真实的 HttpServletRequestHttpServletResponse;RequestContext 扩展于 ConcurrentHashMap ,所以任何的信息基本都能存储;

3.2 过滤器类型

过滤器类型就对应了 zuul Request 的整个生命周期,具体的流程可以参照来自zuul官网下图;

  1. PRE 过滤器 在 routing 到 origin 之前执行;主要包括请求认证,选择origin server , debug日志信息;
  2. ROUTING 过滤器 在 routing 到 origin 之间执行; 建立和发送亲求,支持Apache HttpClient 和 Netflix Ribbon
  3. POST 过滤器 在 routing 到 origin 之后 执行;处理响应信息,比如添加响应头,收集统计信息和指标,将响应输送给客户端;
  4. ERROR 过滤器,当发生异常时就会执行;

技术图片

3.3 自定义filter

自定义filter需要实现 ZuulFilter ;主要实现方法如下

  1. filterOrder 定义过滤器执行顺序;官网默认不同的过滤器顺序如下 PRE_DECORATION_FILTER_ORDERSIMPLE_HOST_ROUTING_FILTER_ORDER, PRE_DECORATION_FILTER_ORDER
  2. filterType 定义过滤器类型;通常就是 PRE_TYPE , ROUTE_TYPE, POST_TYPE
  3. shouldFilter 判定是否执行过滤器
  4. run 执行过滤器

如下代码中是一个PRE过滤器,简单实现了个业务逻辑,对请求的信息进行日志跟踪,获得request上下文进行自定义业务逻辑操作;

/**
 * @Author lsc
 * <p> 前置过滤器示例 </p>
 */
@Component
public class QueryParamPreFilter extends ZuulFilter {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public String filterType() {
        return  PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        // 读者可以拿到请求上下文做业务判断是否执行过滤器
       return true;
    }

    @Override
    public Object run() throws ZuulException {
        System.out.println("----pre filter  be excuted");
        //// 获得当前request 请求上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        // 获得 request
        HttpServletRequest request = ctx.getRequest();
        // 获得远程主机 ip
        String remoteHost = request.getRemoteHost();
        // 获得请求参数
        String username = request.getParameter("username");
        // 打印日志信息
        logger.info("the remote host is {} and params is {}",remoteHost,username);
        // 设置 key
        if (username!=null){
            ctx.put("zszxz", "you can set service");
        }
        return null;
    }
}

执行结果

----pre filter  be excuted
2020-01-30 17:40:22.472  INFO 20792 --- [nio-8100-exec-4] c.z.z.server.filter.QueryParamPreFilter  : the remote host is 0:0:0:0:0:0:0:1 and params is zszxz

四文件上传

4.1 application.yml

在实现文件上传之前需要给配置文件中zuul加上超时设置,和文件大小限制

spring:
  application:
    name: zuul-server # 应用名称
  servlet:
    multipart:
      max-file-size: 200MB #单个文件上传大小
      max-request-size: 600MB #连续上传文件大小
      location: / #临时目录
      
# hystrix 超时设置
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000
            
# ribbon 超时设置
ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 60000
  

4.2 controller

以下是一个简单的文件上传示例;

/**
 * @Author lsc
 * <p>zuul文件上传 </p>
 */
@RestController
public class ZuulFileUploadController {

    @PostMapping("/file/upload")
    public String fileUpload(@RequestParam("file") MultipartFile file) throws IOException {
        // 上传简单文件名
        String originalFilename = file.getOriginalFilename();
        byte[] bytes = file.getBytes();
        File saveFile = new File(originalFilename);
        FileCopyUtils.copy(bytes,saveFile);
        return saveFile.getAbsolutePath();
    }
}

4.3 测试

简单的通过postman测试如下,正确的返回了图片所在的路径;

技术图片

五 参考文档

Netflix-zuul https://github.com/Netflix/zuul/

springcloud官方文档https://cloud.spring.io/spring-cloud-static/Finchley.SR4/single/spring-cloud.html

以上是关于springcloud-zuul进阶篇的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud-Zuul(二):自定义Filter及Zuul内部路由源码解析

Kotlin基础从入门到进阶系列讲解(基础篇)Fragment的基本使用

Kotlin基础从入门到进阶系列讲解(基础篇)Fragment的基本使用

SpringCloud-Zuul

springcloud-zuul路由网关

我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情