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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/110242.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C】C语言文件操作

1.为什么使用文件 我们前面学习结构体时&#xff0c;写通讯录的程序&#xff0c;当通讯录运行起来的时候&#xff0c;可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯录中的数据自然就不存在了&#xff0c;等下…

超全整理,Jmeter性能测试-脚本error报错排查/分布式压测(详全)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能脚本error报错…

域名系统 DNS

DNS 概述 域名系统 DNS(Domain Name System)是因特网使用的命名系统&#xff0c;用来把便于人们使用的机器名字转换成为 IP 地址。域名系统其实就是名字系统。为什么不叫“名字”而叫“域名”呢&#xff1f;这是因为在这种因特网的命名系统中使用了许多的“域(domain)”&#x…

S5PV210裸机(九):ADC

本文主要探讨210的ADC相关知识。 ADC ADC:模数转换&#xff08;模拟信号转数字信号&#xff09; 量程:模拟电压信号范围(210为0&#xff5e;3.3V) 精度:若10二进制位来表示精度&#xff08;210为10位或12位&#xff09;,量…

线性代数 第三章 向量

一、运算 加法、数乘、内积 施密特正交化 二、线性表出 概念&#xff1a;如果&#xff0c;则称可由线性表出&#xff08;k不要求不全为0&#xff09; 判定&#xff1a; 非齐次线性方程组有解无关&#xff0c;相关 如果两个向量组可以互相线性表出&#xff0c;则称这两个…

Xilinx 7 系列 1.8V LVDS 和 2.5V LVDS 信号之间的 LVDS 兼容性

如果通过LVDS进行接口&#xff0c;可以按照以程图中的步骤操作&#xff0c;以确保满足正确使用LVDS的所有要求。 40191 - 7 系列 - 1.8V LVDS 和 2.5V LVDS 信号之间的 LVDS 兼容性 与LVDS兼容驱动器和接收器连接时&#xff0c;7系列LVDS和LVDS_25输入和输出应该不存在兼容性问…

案例分析真题-系统建模

案例分析真题-系统建模 2009年真题 【问题1】 【问题2】 【问题3】 2012年真题 【问题1】 【问题2】 【问题3】 2014年真题 【问题1】 【问题2】 骚戴理解&#xff1a;这个题目以前经常考&#xff0c;不知道今年会不会考&#xff0c;判断的话就是看加工有没有缺少输入和输出&a…

C++面试——多线程详解

C11提供了语言层面上的多线程&#xff0c;包含在头文件<thread>中。它解决了跨平台的问题&#xff0c;提供了管理线程、保护共享数据、线程间同步操作、原子操作等类。C11 新标准中引入了5个头文件来支持多线程编程&#xff0c;如下图所示&#xff1a; 多进程与多线程 多…

SSH 无密登录设置

1 &#xff09; 配置 ssh &#xff08;1&#xff09;基本语法 ssh 另一台电脑的 IP 地址&#xff08;2&#xff09;ssh 连接时出现 Host key verification failed 的解决方法 [libaihadoop102 ~]$ ssh hadoop103 ➢ 如果出现如下内容 Are you sure you want to continue c…

MAC缓解WebUI提示词反推

当前环境信息&#xff1a; 在mac上安装好stable diffusion后&#xff0c;能做图片生成了之后&#xff0c;遇到一些图片需要做提示词反推&#xff0c;这个时候需要下载一个插件&#xff0c;参考&#xff1a; https://gitcode.net/ranting8323/stable-diffusion-webui-wd14-tagg…

mac 安装homebrew ,golang

mac 安装homebrew ,golang 安装homebrew安装golang选择 apple arm 版本安装配置环境变量 安装homebrew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"回车执行指令后&#xff0c;根据提示操作。具体包括以下提示操作&am…

ios 代码上下文截屏之后导致的图片异常问题

业务场景&#xff0c;之前是直接将当前的collectionview截长屏操作&#xff0c;第一次截图会出现黑色部分原因是视图未完全布局&#xff0c;原因是第一次使用了Masonry约束然后再截图的时候进行了frame赋值&#xff0c;可以查看下Masonry约束和frame的冲突&#xff0c;全部修改…

除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂…

Qt 重写QSlider简单实现滑动解锁控件(指定百分比回弹效果)

组件效果图&#xff1a; 应用场景&#xff1a; 用于滑动解锁相关场景&#xff0c;Qt的控件鼠标监听机制对于嵌入式设备GUI可触摸屏依旧可用。 实现方式&#xff1a; 主要是通过继承QSlider以及搭配使用QStyleOptionSlider来实现效果。 注意细则&#xff1a; QStyleOption…

【IDEA】每个方法之间如何设置分隔线

修改后效果&#xff1a; 各个方法之间出现了分隔线

洞察运营机会的数据分析利器

这套分析方法包括5个分析工具&#xff1a; 用“描述性统计”来快速了解数据的整体特点。用“变化分析”来寻找数据的问题和突破口。用“指标体系”来深度洞察变化背后的原因。用“相关性分析”来精确判断原因的影响程度。用“趋势预测”来科学预测未来数据的走势&#xff0c;

浅谈js代码的封装方法(2023.10.30)

常见的js代码封装方法 2023.10.30 需求1、js代码封装的优缺点2、js代码封装方式2.1 方式一&#xff1a;function function declarations2.1.1 示例 2.2 方式二&#xff1a;class2.2.1 class declarations2.2.2 Class expressions 2.3 变量函数2.4 变量闭包匿名函数2.5 闭包函数…

vscode开启emmet语法

需要在setting.json中添加配置 首先进入设置&#xff0c;然后点击右上角 Vue项目添加如下配置 "emmet.syntaxProfiles": { "vue-html": "html", "vue": "html" },React项目添加如下配置 "emmet.includeLanguages&quo…

剑指JUC原理-5.synchronized底层原理

Java对象头 以32位虚拟机为例&#xff1a; 普通对象 在Java虚拟机中&#xff0c;每个对象都有一个对象头&#xff08;Object Header&#xff09;&#xff0c;其中包含了一些用于管理对象的元数据信息。对象头通常由两部分组成&#xff1a;mark word&#xff08;标记字&#x…