精华内容
下载资源
问答
  • 如今建筑智能化集成度越来越高,对于网络设备应用也越来越了,在计算机网络体系几样网络设备或者说网络名词出现的频率相当的高,包括:中继器、集线器、网桥、交换机、路由器和网关。其实,弄清楚这几...

    831125769cccea235b97f7c1a52100c7.png

    如今建筑智能化集成度越来越高,对于网络设备应用也越来越多了,在计算机网络体系中,有几样网络设备或者说网络名词出现的频率相当的高,包括有:中继器、集线器、网桥、交换机、路由器和网关。

    其实,弄清楚这几个计算机网络的名词并不困难,如果能以计算机网络层次的概念给它们划清界限的话,那就很容易把它们区分出来。

    那我们现在就有条理地梳理一下它们各自的含义和作用,以及它们之间的联系。

    那我们首先看一下这些网络设备分别处于计算机网络的哪些层次:

    一、中继器

    中继器(Repeater)是连接网络线路的一种装置,常用于两个网络节点之间物理信号的双向转发工作。中继器是最简单的网络互联设备,主要完成物理层的功能,负责在两个节点的物理层上按位传递信息,完成信号的复制、调整和放大功能,以此来延长网络的长度。它在OSI参考模型中的位置物理层。

    20c120da6e4652df5ae364833aaf6eac.png

    由于存在损耗, 在线路上传输的信号功率会逐渐衰减,衰减到一定程度时将造成信号失真,因此会导致接收错误。中继器就是为解决这一问题而设计的。中继器完成物理线路的连接,对衰减的信号进行放大,保持与原数据相同。

    它属于一种模拟设备,用于连接两根电缆段。中继器不理解帧、分组和头的概念,他们只理解电压值。

    总结:中继器,就是简单的信号放大器,信号在传输的过程中是要衰减的,中继器的作用就是将信号放大,使信号能传的更远。

    二、集线器

    集线器(Hub)是中继器的一种形式,区别在于集线器能够提供多端口服务,也称为多口中继器。集线器在OSI/RM中的物理层。

    a6ad4baea430cd04dd1d587948fd7a50.png

    总结:集线器,差不多就是个多端口的中继器,把每个输入端口的信号放大再发到别的端口去,集线器可以实现多台计算机之间的互联,因为它有很多的端口,每个口都能连计算机。

    三、网桥

    网桥(Bridge)是一个局域网与另一个局域网之间建立连接的桥梁。网桥是属于数据链路层的一种设备,它的作用是扩展网络和通信手段,在各种传输介质中转发数据信号,扩展网络的距离。

    同时又有选择地将现有地址的信号从一个传输介质发送到另一个传输介质,并能有效地限制两个介质系统中无关紧要的通信。

    5ea994fb6894603459b60d6f6c1a38e1.png

    总结:网桥工作在数据链路层,将两个LAN连起来,根据MAC地址来转发帧,可以看作一个“低层的路由器”。

    四、交换机

    交换机(Swich)工作在第二层(即数据链路层),它要比集线器智能一些,它能分辨出帧中的源MAC地址和目的MAC地址,因此可以在任意两个端口间建立联系,在数据帧的始发者和目标接收者之间建立临时的交换路径,使数据帧直接由源地址到达目的地址。

    交换机通过对信息进行重新生成,并经过内部处理后转发至指定端口,具备自动寻址能力和交换作用。但是 交换机并不懂得IP地址,它只知道MAC地址。

    384b19b2b507c16bda07215c2bf41cb9.png

    交换机是使用硬件来完成以往网桥使用软件来完成过滤、学习和转发过程的任务。交换机速度比HUB快,这是由于HUB不知道目标地址在何处,发送数据到所有的端口。

    交换机中有一张MAC地址表,如果知道目标地址在何处,就把数据发送到指定地点,如果它不知道就发送到所有的端口。这样过滤可以帮助降低整个网络的数据传输量,提高效率。但是交换机的功能还不止如此,它可以把网络拆解成网络分支、分割网络数据流,隔离分支中发生的故障,这样就可以减少每个网络分支的数据信息流量而使每个网络更有效,提高整个网络效率。

    现代交换机是这样处理数据帧的:一旦目标头域(目标地址)已经进来了,尽管帧的其他部分还没有到达,则只要输出线路可以使用,交换机就开始转发该帧,而不需理会帧后面的内容,也即是说交换机并没有使用“存储—转发”交换方式。

    总结:交换机,可以理解为高级的网桥,他有网桥的功能,但性能比网桥强。交换机和网桥的细微差别就在于:交换机常常用来连接独立的计算机,而网桥连接的目标是LAN,所以交换机的端口较网桥多。

    五、路由器

    路由器(Router)工作在第三层(即网络层),它比交换机还要“聪明”一些,它能理解数据中的IP地址,如果它接收到一个数据包,就检查其中的IP地址,如果目标地址是本地网络的就不理会,如果是其他网络的,就将数据包转发出本地网络。

    与工作在网络物理层,从物理上划分网段的交换机不同,路由器使用专门的软件协议从逻辑上对整个网络进行划分。

    例如,一台支持IP协议的路由器可以把网络划分成多个子网段,只有指向特殊IP地址的网络流量才可以通过路由器。当IP子网中的一台主机发送IP分组给同一IP子网的另一台主机时,它将直接把IP分组送到网络上,对方就能收到。而要送给不同IP于网上的主机时,它要选择一个能到达目的子网上的路由器,把IP分组送给该路由器,由路由器负责把IP分组送到目的地。

    如果没有找到这样的路由器,主机就把IP分组送给一个称为“缺省网关(default gateway)”的路由器上。对于每一个接收到的数据包,路由器都会重新计算其校验值,并写入新的物理地址。

    网络中的设备用它们的网络地址(TCP/IP网络中为IP地址)互相通信。IP地址是与硬件地址无关的“逻辑”地址。目前TCP/IP网络,全部是通过路由器互连起来的,Internet就是成千上万个IP子网通过路由器互连起来的国际性网络。

    c264dc96ffe5b5ae2b8e05d78f3bd9d8.png

    路由器用于连接多个逻辑上分开的网络,几个使用不同协议和体系结构的网络。路由器利用网络层定义的“逻辑”上的网络地址(即IP地址)来区别不同的网络,实现网络的互连和隔离,保持各个网络的独立性。

    当一个子网传输到另外一个子网时,可以用路由器完成。它具有判断网络地址和选择路径的功能,过滤和分隔网络信息流。一方面能够跨越不同的物理网络类型(DDN、FDDI、以太网等等),另一方面在逻辑上将整个互连网络分割成逻辑上独立的网络单位,使网络具有一定的逻辑结构。

    总结:路由器的主要工作就是为经过路由器的每个IP数据包寻找一条最佳传输路径,并将该数据有效地传送到目的站点。路由器的基本功能是,把数据(IP报文)传送到正确的网络。

    六、网关

    网关(Gateway)又称网间连接器、协议转换器。

    网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。网关是一种充当转换重任的计算机系统或设备。

    使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。

    总结:网关,通过字面意思解释就是网络的关口。从技术角度来解释,就是连接两个不同网络的接口,比如局域网的共享上网服务器就是局域网和广域网的接口。

    最后有两个注意问题:

    1、交换机和路由器的区别?

    从应用上说:

    交换机和路由器的使用中最大的区别莫过于路由器内部可实现拨号上网,然后通过共享给多台电脑同时上网,而交换机内部不具有拨号功能,但交换机的作用是将网络信号分流,以实现更多电脑连接共享上网。

    大家可以这样认为,交换机可以将多台电脑连接起来,与交换机互连的电脑本身则具备了互相通信的功能,组建成了一个内部局域网,但需要访问互联网还需要有网络支持,因此交换机一端需要连接到路由器,路由器即可实现交换功能,还可以拨号,实现宽带连接,并将宽带资源分配个交换机使用,这样就实现了多台电脑共享上网。

    从概念上说:

    路由,是三层设备,有选择道路的作用。比如你去罗马,有很多路可以走,怎么走省钱省时间,就是路由要做的,解决你应该按照那条路走的问题。当然还有基于三层的其他功能。

    交换机,是二层设备。他就像你家门前的如或者你们楼道,附近的住户都知道去几层几号怎么走。

    举个例子说明路由器和交换机的配合:我要去找小明借电脑,小明说他不在家,叫我自己去拿吧,同时还告诉我他家的地址是XX路XX小区XX号(好比ip地址),我根据小明告诉我的地址找到了小明的家(路由器的功能,寻找路径)。我进门发现他家居然有10台电脑,哪台是借给我的那台呢?噢,原来小明还告诉我他要借给我的电脑的编号(MAC地址),那样我就可以根据编号找到相应的电脑了。

    在上述的例子中,如果我没有路由器,我就不知道怎么去小明家,更不用说拿到电脑;如果我没有拿到所需的电脑编号,我也拿不到电脑,因为有十台电脑,我不能乱拿;有个特殊情况,如果小明家只有一台电脑呢?那我就不需要编号就可以确定拿哪台电脑,也就是不需要交换机。

    2、为什么有时候还要在路由器的后面先接1台交换机再接计算机?

    路由器是可以直接接电脑等终端设备,为什么标准都是路由器接交换机然后再接电脑等终端,是因为路由器本来就是一个路由设备,用来选路的,不适合大量的数据交换,交换机是用来大量数据交换的,终端在内网的性质就是需要使用交换机,所以标准就是路由器地下接交换机的形式。

    一般是情况就是在路由器下面接交换机,路由器主要起数据转发,也就是寻址、路由的功能,交换机起到用户接入的目的。但是家用的路由器的话直接就接计算机就可以了,而不必考虑再接交换机。

    c0aef099f2ea0c4e4bc729799980fb54.png

    结语:优质内容贵在与同行分享,共同学习,共同进步,共同成长。感谢微信公众平台及大家的支持!

    资料获取方式:在公众号主菜单栏左下角点击“资料获取”!

    9a0954edc3c568159fd01b7016a44159.png

    展开全文
  • 如今建筑智能化集成度越来越高,对于网络设备应用也越来越了,在计算机网络体系几样网络设备或者说网络名词出现的频率相当的高,包括:中继器、集线器、网桥、交换机、路由器和网关。其实,弄清楚这几...

    如今建筑智能化集成度越来越高,对于网络设备应用也越来越多了,在计算机网络体系中,有几样网络设备或者说网络名词出现的频率相当的高,包括有:中继器、集线器、网桥、交换机、路由器和网关。

    其实,弄清楚这几个计算机网络的名词并不困难,如果能以计算机网络层次的概念给它们划清界限的话,那就很容易把它们区分出来。

    那我们现在就有条理地梳理一下它们各自的含义和作用,以及它们之间的联系。

    那我们首先看一下这些网络设备分别处于计算机网络的哪些层次:

    一、中继器

    中继器(Repeater)是连接网络线路的一种装置,常用于两个网络节点之间物理信号的双向转发工作。中继器是最简单的网络互联设备,主要完成物理层的功能,负责在两个节点的物理层上按位传递信息,完成信号的复制、调整和放大功能,以此来延长网络的长度。它在OSI参考模型中的位置物理层。

    f2e7345d7df2fc1c51adddd4a2a51cf3.png

    由于存在损耗, 在线路上传输的信号功率会逐渐衰减,衰减到一定程度时将造成信号失真,因此会导致接收错误。中继器就是为解决这一问题而设计的。中继器完成物理线路的连接,对衰减的信号进行放大,保持与原数据相同。

    它属于一种模拟设备,用于连接两根电缆段。中继器不理解帧、分组和头的概念,他们只理解电压值。

    总结:中继器,就是简单的信号放大器,信号在传输的过程中是要衰减的,中继器的作用就是将信号放大,使信号能传的更远。

    二、集线器

    集线器(Hub)是中继器的一种形式,区别在于集线器能够提供多端口服务,也称为多口中继器。集线器在OSI/RM中的物理层。

    b306c7a541d699956cae48e7bd0c95a7.png

    总结:集线器,差不多就是个多端口的中继器,把每个输入端口的信号放大再发到别的端口去,集线器可以实现多台计算机之间的互联,因为它有很多的端口,每个口都能连计算机。

    三、网桥

    网桥(Bridge)是一个局域网与另一个局域网之间建立连接的桥梁。网桥是属于数据链路层的一种设备,它的作用是扩展网络和通信手段,在各种传输介质中转发数据信号,扩展网络的距离。

    同时又有选择地将现有地址的信号从一个传输介质发送到另一个传输介质,并能有效地限制两个介质系统中无关紧要的通信。

    7f16ada053c1e9f4ed4c0b0592a349a7.png

    总结:网桥工作在数据链路层,将两个LAN连起来,根据MAC地址来转发帧,可以看作一个“低层的路由器”。

    四、交换机

    交换机(Swich)工作在第二层(即数据链路层),它要比集线器智能一些,它能分辨出帧中的源MAC地址和目的MAC地址,因此可以在任意两个端口间建立联系,在数据帧的始发者和目标接收者之间建立临时的交换路径,使数据帧直接由源地址到达目的地址。

    交换机通过对信息进行重新生成,并经过内部处理后转发至指定端口,具备自动寻址能力和交换作用。但是 交换机并不懂得IP地址,它只知道MAC地址。

    5df4abac4cc31dfec1001687fc55066b.png

    交换机是使用硬件来完成以往网桥使用软件来完成过滤、学习和转发过程的任务。交换机速度比HUB快,这是由于HUB不知道目标地址在何处,发送数据到所有的端口。

    交换机中有一张MAC地址表,如果知道目标地址在何处,就把数据发送到指定地点,如果它不知道就发送到所有的端口。这样过滤可以帮助降低整个网络的数据传输量,提高效率。但是交换机的功能还不止如此,它可以把网络拆解成网络分支、分割网络数据流,隔离分支中发生的故障,这样就可以减少每个网络分支的数据信息流量而使每个网络更有效,提高整个网络效率。

    现代交换机是这样处理数据帧的:一旦目标头域(目标地址)已经进来了,尽管帧的其他部分还没有到达,则只要输出线路可以使用,交换机就开始转发该帧,而不需理会帧后面的内容,也即是说交换机并没有使用“存储—转发”交换方式。

    总结:交换机,可以理解为高级的网桥,他有网桥的功能,但性能比网桥强。交换机和网桥的细微差别就在于:交换机常常用来连接独立的计算机,而网桥连接的目标是LAN,所以交换机的端口较网桥多。

    五、路由器

    路由器(Router)工作在第三层(即网络层),它比交换机还要“聪明”一些,它能理解数据中的IP地址,如果它接收到一个数据包,就检查其中的IP地址,如果目标地址是本地网络的就不理会,如果是其他网络的,就将数据包转发出本地网络。

    与工作在网络物理层,从物理上划分网段的交换机不同,路由器使用专门的软件协议从逻辑上对整个网络进行划分。

    例如,一台支持IP协议的路由器可以把网络划分成多个子网段,只有指向特殊IP地址的网络流量才可以通过路由器。当IP子网中的一台主机发送IP分组给同一IP子网的另一台主机时,它将直接把IP分组送到网络上,对方就能收到。而要送给不同IP于网上的主机时,它要选择一个能到达目的子网上的路由器,把IP分组送给该路由器,由路由器负责把IP分组送到目的地。

    如果没有找到这样的路由器,主机就把IP分组送给一个称为“缺省网关(default gateway)”的路由器上。对于每一个接收到的数据包,路由器都会重新计算其校验值,并写入新的物理地址。

    网络中的设备用它们的网络地址(TCP/IP网络中为IP地址)互相通信。IP地址是与硬件地址无关的“逻辑”地址。目前TCP/IP网络,全部是通过路由器互连起来的,Internet就是成千上万个IP子网通过路由器互连起来的国际性网络。

    72d7e07222ff903763efa4dbdf0bb55c.png

    路由器用于连接多个逻辑上分开的网络,几个使用不同协议和体系结构的网络。路由器利用网络层定义的“逻辑”上的网络地址(即IP地址)来区别不同的网络,实现网络的互连和隔离,保持各个网络的独立性。

    当一个子网传输到另外一个子网时,可以用路由器完成。它具有判断网络地址和选择路径的功能,过滤和分隔网络信息流。一方面能够跨越不同的物理网络类型(DDN、FDDI、以太网等等),另一方面在逻辑上将整个互连网络分割成逻辑上独立的网络单位,使网络具有一定的逻辑结构。

    总结:路由器的主要工作就是为经过路由器的每个IP数据包寻找一条最佳传输路径,并将该数据有效地传送到目的站点。路由器的基本功能是,把数据(IP报文)传送到正确的网络。

    六、网关

    网关(Gateway)又称网间连接器、协议转换器。

    网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。网关是一种充当转换重任的计算机系统或设备。

    使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。

    总结:网关,通过字面意思解释就是网络的关口。从技术角度来解释,就是连接两个不同网络的接口,比如局域网的共享上网服务器就是局域网和广域网的接口。

    最后有两个注意问题:

    1、交换机和路由器的区别?

    从应用上说:

    交换机和路由器的使用中最大的区别莫过于路由器内部可实现拨号上网,然后通过共享给多台电脑同时上网,而交换机内部不具有拨号功能,但交换机的作用是将网络信号分流,以实现更多电脑连接共享上网。

    大家可以这样认为,交换机可以将多台电脑连接起来,与交换机互连的电脑本身则具备了互相通信的功能,组建成了一个内部局域网,但需要访问互联网还需要有网络支持,因此交换机一端需要连接到路由器,路由器即可实现交换功能,还可以拨号,实现宽带连接,并将宽带资源分配个交换机使用,这样就实现了多台电脑共享上网。

    从概念上说:

    路由,是三层设备,有选择道路的作用。比如你去罗马,有很多路可以走,怎么走省钱省时间,就是路由要做的,解决你应该按照那条路走的问题。当然还有基于三层的其他功能。

    交换机,是二层设备。他就像你家门前的如或者你们楼道,附近的住户都知道去几层几号怎么走。

    举个例子说明路由器和交换机的配合:我要去找小明借电脑,小明说他不在家,叫我自己去拿吧,同时还告诉我他家的地址是XX路XX小区XX号(好比ip地址),我根据小明告诉我的地址找到了小明的家(路由器的功能,寻找路径)。我进门发现他家居然有10台电脑,哪台是借给我的那台呢?噢,原来小明还告诉我他要借给我的电脑的编号(MAC地址),那样我就可以根据编号找到相应的电脑了。

    在上述的例子中,如果我没有路由器,我就不知道怎么去小明家,更不用说拿到电脑;如果我没有拿到所需的电脑编号,我也拿不到电脑,因为有十台电脑,我不能乱拿;有个特殊情况,如果小明家只有一台电脑呢?那我就不需要编号就可以确定拿哪台电脑,也就是不需要交换机。

    2、为什么有时候还要在路由器的后面先接1台交换机再接计算机?

    路由器是可以直接接电脑等终端设备,为什么标准都是路由器接交换机然后再接电脑等终端,是因为路由器本来就是一个路由设备,用来选路的,不适合大量的数据交换,交换机是用来大量数据交换的,终端在内网的性质就是需要使用交换机,所以标准就是路由器地下接交换机的形式。

    一般是情况就是在路由器下面接交换机,路由器主要起数据转发,也就是寻址、路由的功能,交换机起到用户接入的目的。但是家用的路由器的话直接就接计算机就可以了,而不必考虑再接交换机。

    展开全文
  • 服务网关和Zuul 为什么要有服务网关: 我们都知道在微服务架构,系统...我们已经知道,在微服务架构,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N微...

    服务网关和Zuul

    为什么要有服务网关:

    我们都知道在微服务架构中,系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?难道要一个个的去调用吗?很显然这是不太实际的,我们需要有一个统一的接口与这些微服务打交道,这就是我们需要服务网关的原因。

    我们已经知道,在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。比如:用户查看一个商品的信息,它可能包含商品基本信息、价格信息、评论信息、折扣信息、库存信息等等,而这些信息获取则来源于不同的微服务,诸如产品系统、价格系统、评论系统、促销系统、库存系统等等,那么要完成用户信息查看则需要调用多个微服务,这样会带来几个问题:

    1. 客户端多次请求不同的微服务,增加客户端代码或配置编写的复杂性
    2. 认证繁杂,访问每个服务都要进行一次认证
    3. 每个服务都通过http访问,导致http请求增加,效率不高拖慢系统性能
    4. 多个服务存在跨域请求问题,处理起来比较复杂

    如下图所示:
    Spring Cloud Zuul 快速入门

    我们该如何解决这些问题呢?我们可以尝试想一下,不要让前端直接知道后台诸多微服务的存在,我们的系统本身就是从业务领域的层次上进行划分,形成多个微服务,这是后台的处理方式。对于前台而言,后台应该仍然类似于单体应用一样,一次请求即可,于是我们可以在客户端和服务端之间增加一个API网关,所有的外部请求先通过这个微服务网关。它只需跟网关进行交互,而由网关进行各个微服务的调用。

    这样的话,我们就可以解决上面提到的问题,同时开发就可以得到相应的简化,还可以有如下优点:

    1. 减少客户端与微服务之间的调用次数,提高效率
    2. 便于监控,可在网关中监控数据,可以做统一切面任务处理
    3. 便于认证,只需要在网关进行认证即可,无需每个微服务都进行认证
    4. 降低客户端调用服务端的复杂度

    这里可以联想到一个概念,面向对象设计中的门面模式,即对客户端隐藏细节,API网关也是类似的东西,只不过叫法不同而已。它是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等等。示意图:
    Spring Cloud Zuul 快速入门

    总结一下,服务网关大概就是四个功能:统一接入、流量管控、协议适配、安全维护。而在目前的网关解决方案里,有Nginx+ Lua、Kong、Tyk以及Spring Cloud Zuul等等。这里以Zuul为例进行说明,它是Netflix公司开源的一个API网关组件,Spring Cloud对其进行二次封装做到开箱即用。同时,Zuul还可以与Spring Cloud中的Eureka、Ribbon、Hystrix等组件配合使用。

    可以说,Zuul实现了两个功能,路由转发和过滤器:

    • 路由转发:接受请求,转发到后端服务
    • 过滤器:提供一系列过滤器完成权限、日志、限流等切面任务。
    • 可以说路由+过滤器=Zuul

    服务网关的要素:

    • 网关作为唯一的入口,所以稳定性和高可用是跑不了了
    • 以及具备良好的并发性能
    • 安全性,确保服务不被恶意访问
    • 扩展性,网关容易成为吞吐量的瓶颈,所以需要便于扩展

    Zuul的四种过滤器API:

    • 前置(Pre)
    • 路由(Route)
    • 后置(Post)
    • 错误(Error)

    zuul前后置过滤器的典型应用场景:

    • 前置(Pre)
      • 限流
      • 鉴权
      • 参数校验调整
    • 后置(Post)
      • 统计
      • 日志

    Zuul的核心是一系列过滤器,开发者通过实现过滤器接口,可以做大量切面任务,即AOP思想的应用。Zuul的过滤器之间没有直接的相互通信,而是通过本地ThreadLocal变量进行数据传递的。Zuul架构图:
    Spring Cloud Zuul 快速入门

    在Zuul里,一个请求的生命周期:
    Spring Cloud Zuul 快速入门


    Zuul:路由转发,排除和自定义

    本小节我们来学习如何使用服务网关,也就是Spring Cloud Zuul这个组件,首先新建一个项目,选择如下模块:
    Spring Cloud Zuul 快速入门

    pom.xml配置的依赖如下:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    项目创建好后,将application.properties改为bootstrap.yml,编辑内容如下:

    spring:
      application:
        name: api-gateway
      cloud:
        config:
          discovery:
            enabled: true
            service-id: CONFIG
          profile: dev
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/

    注:我这里使用了配置中心,若对此不熟悉的话,可以参考我另一篇文章:Spring Cloud Config - 统一配置中心

    在启动类中,加上@EnableZuulProxy注解,代码如下:

    package org.zero.springcloud.apigateway;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
    
    @SpringBootApplication
    @EnableZuulProxy
    public class ApiGatewayApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ApiGatewayApplication.class, args);
        }
    }

    完成以上配置后启动这个项目,我这里项目启动是正常的。然后我们来通过这个网关访问一下商品服务中获取商品列表的接口。如下:
    Spring Cloud Zuul 快速入门

    访问地址说明:

    • 该zuul项目跑在8951端口上
    • 第一个/product是需要访问的服务的名称
    • 后面跟的/buyer/product/list是商品服务中获取商品列表的接口地址

    只要是在eureka上注册的服务都能够通过zuul进行转发,例如我通过zuul来访问config的配置文件:
    Spring Cloud Zuul 快速入门

    如上,可以看到,报错了,网关超时。这是因为默认情况下,zuul的熔断机制超时时间是2秒,当一个服务响应的时间较长就会报网关超时错误。

    我们在配置文件中,加上如下超时时间的配置即可:
    Spring Cloud Zuul 快速入门

    ribbon.ReadTimeout, ribbon.SocketTimeout这两个就是ribbon超时时间设置,当在yml写时,应该是没有提示的,给人的感觉好像是不是这么配的一样,其实不用管它,直接配上就生效了。

    还有zuul.host.connect-timeout-millis, zuul.host.socket-timeout-millis这两个配置,这两个和上面的ribbon都是配超时的。区别在于,如果路由方式是serviceId的方式,那么ribbon的生效,如果是url的方式,则zuul.host开头的生效。(此处重要!使用serviceId路由和url路由是不一样的超时策略)

    如果你在zuul配置了熔断fallback的话,熔断超时也要配置,即hystrix那段配置。不然如果你配置的ribbon超时时间大于熔断的超时,那么会先走熔断,相当于你配的ribbon超时就不生效了。

    现在重启项目,再次访问之前的地址,就不会出现网关超时的错误了:
    Spring Cloud Zuul 快速入门

    之前我们访问的都是GET类型的接口,我们来看看POST类型的是否能够正常访问。如下:
    Spring Cloud Zuul 快速入门

    每次请求某个服务的接口,都需要带上这个服务的名称。有没有办法可以自定义这个规则呢?答案是有的,在配置文件中,增加路由的自定义配置:

    zuul:
      routes:
        myProduct:
          path: /myProduct/**
          serviceId: product

    说明:

    • myProduct 自定义的前缀
    • path 匹配的地址
    • product 路由到哪个服务

    重启项目,测试如下:
    Spring Cloud Zuul 快速入门

    在项目启动的时候,我们也可以在控制台中查看到zuul所有的路由规则:
    Spring Cloud Zuul 快速入门

    如果我们有些服务的接口不希望对外暴露,只希望在服务间调用,那么就可以在配置文件中,增加路由排除的配置。例如我不希望listForOrder被外部访问,则在配置文件中,增加如下配置即可:

    zuul:
      ...
      ignored-patterns:
        - /myProduct/buyer/product/listForOrder
        - /product/buyer/product/listForOrder

    重启项目,这时访问就会报404了。如下:
    Spring Cloud Zuul 快速入门

    还可以使用通配符进行匹配。如下示例:

    zuul:
      ...
      ignored-patterns:
        - /**/buyer/product/listForOrder

    Zuul:Cookie和动态路由

    我们在web开发中,经常会利用到cookie来保存用户的登录标识。但我们使用了zuul组件后,默认情况下,cookie是无法直接传递给服务的,因为cookie默认被列为敏感的headers。所以我们需要在配置文件中,将sensitiveHeaders的值置空。如下:

    zuul:
      ...
      routes:
        myProduct:
          path: /myProduct/**
          serviceId: product
          sensitiveHeaders:  # 置空该属性的值即可

    我们每次配置路由信息都需要重启项目,显得很麻烦,在线上环境也不能这样随便重启项目。所以我们得实现动态路由的功能,实现动态路由其实就利用一下我们之前实现的动态刷新配置文件的功能即可。首先把Zuul路由相关的配置剪切到git上,如下:
    Spring Cloud Zuul 快速入门

    注:我这里使用了配置中心,若对此不熟悉的话,可以参考我另一篇文章:Spring Cloud Config - 统一配置中心

    在pom.xml文件中,增加如下依赖项:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-client</artifactId>
    </dependency>

    然后在bootstrap.yml中,增加rabbitmq的配置。如下:

    spring:
      application:
        name: api-gateway
      cloud:
        config:
          discovery:
            enabled: true
            service-id: CONFIG
          profile: dev
      rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: admin
        password: admin
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/

    最后在项目中创建一个config包,在该包中创建一个ZuulConfig配置类,用于加载配置文件中的配置。代码如下:

    package org.zero.springcloud.apigateway.config;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
    import org.springframework.stereotype.Component;
    
    /**
     * @program: api-gateway
     * @description: 网关路由配置类
     * @author: 01
     * @create: 2018-08-25 15:51
     **/
    @Component
    public class ZuulConfig {
    
        @RefreshScope
        @ConfigurationProperties("zuul")
        public ZuulProperties zuulProperties(){
            return new ZuulProperties();
        }
    }

    完成以上配置后,重启项目,即可实现动态路由了,例如我现在把myProduct改成yourProduct,如下:
    Spring Cloud Zuul 快速入门

    此时无需重启项目,访问新的地址即可。如下:
    Spring Cloud Zuul 快速入门


    Zuul的高可用

    • 因为Zuul也属于一个微服务,所以我们将多个Zuul节点注册到Eureka Server即可实现Zuul的高可用性
    • 将Nginx和Zuul “混搭”,利用nginx做负载均衡,转发到多个Zuul上
    展开全文
  • 为什么要有服务网关? 我们都知道在微服务架构,系统会被...我们已经知道,在微服务架构,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N微服务的接口完成...
        

    为什么要有服务网关?

    我们都知道在微服务架构中,系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?难道要一个个的去调用吗?很显然这是不太实际的,我们需要有一个统一的接口与这些微服务打交道,这就是我们需要服务网关的原因。

    我们已经知道,在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。比如:用户查看一个商品的信息,它可能包含商品基本信息、价格信息、评论信息、折扣信息、库存信息等等,而这些信息获取则来源于不同的微服务,诸如产品系统、价格系统、评论系统、促销系统、库存系统等等,那么要完成用户信息查看则需要调用多个微服务,这样会带来几个问题:

    • 客户端多次请求不同的微服务,增加客户端代码或配置编写的复杂性
    • 认证繁杂,访问每个服务都要进行一次认证
    • 每个服务都通过http访问,导致http请求增加,效率不高拖慢系统性能
    • 多个服务存在跨域请求问题,处理起来比较复杂
    11464886-a3316d1cc7c899eb.png

    我们该如何解决这些问题呢?我们可以尝试想一下,不要让前端直接知道后台诸多微服务的存在,我们的系统本身就是从业务领域的层次上进行划分,形成多个微服务,这是后台的处理方式。对于前台而言,后台应该仍然类似于单体应用一样,一次请求即可,于是我们可以在客户端和服务端之间增加一个API网关,所有的外部请求先通过这个微服务网关。它只需跟网关进行交互,而由网关进行各个微服务的调用。

    这样的话,我们就可以解决上面提到的问题,同时开发就可以得到相应的简化,还可以有如下优点:

    • 减少客户端与微服务之间的调用次数,提高效率
    • 便于监控,可在网关中监控数据,可以做统一切面任务处理
    • 便于认证,只需要在网关进行认证即可,无需每个微服务都进行认证
    • 降低客户端调用服务端的复杂度

    这里可以联想到一个概念,面向对象设计中的门面模式,即对客户端隐藏细节,API网关也是类似的东西,只不过叫法不同而已。它是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等等。示意图:


    11464886-446d47943edb92f2.png

    总结一下,服务网关大概就是四个功能:统一接入流量管控协议适配安全维护。而在目前的网关解决方案里,有Nginx+ Lua、Spring Cloud Zuul以及Spring Cloud Gateway等等。这里以Spring Cloud Gateway为例进行说明。

    Spring Cloud Gateway简介

    Spring Cloud Gateway是Spring Cloud体系的第二代网关组件,基于Spring 5.0的新特性WebFlux进行开发,底层网络通信框架使用的是Netty,所以其吞吐量高、性能强劲,未来将会取代第一代的网关组件Zuul。Spring Cloud Gateway可以通过服务发现组件自动转发请求,默认集成了Ribbon做负载均衡,以及默认使用Hystrix对网关进行保护,当然也可以选择其他的容错组件,例如Sentinel

    优点:

    • 性能强劲:是第一代网关Zuul的1.6倍
    • 功能强大:内置了很多实用的功能,例如转发、监控、限流等
    • 设计优雅,容易扩展

    缺点:

    • 其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,有一定的学习成本
    • 不能在Servlet容器下工作,也不能构建成WAR包,即不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行
    • 不支持Spring Boot 1.x,需2.0及更高的版本

    核心概念

    • Route(路由)
      Spring Cloud Gateway的基础元素,可简单理解成一条转发规则。包含:ID、目标URL、Predicate集合以及Filter集合

    这是一段比较典型的Gateway路由配置:

    spring:
      cloud:
        gateway:
          routes:
          - id: user-center  # 唯一标识,通常使用服务id
            uri: lb://user-center  # 目标URL,lb代表从注册中心获取服务,lb是Load Balance的缩写
            predicates:
            # Predicate集合
              - Path=/zj/cloud/v1/user-center/**  # 匹配转发路径
            filters:
            # Filter集合
              - StripPrefix=4  # 从第几级开始转发
    

    2. Predicate(谓词)
    java.util.function.Predicate这个接口,Gateway使用Predicate实现路由的匹配条件
    3. Filter(过滤器)
    与我们平时使用的Servlet编程模型里的过滤器概念类似,同样可以用于修改请求以及响应数据,可以利用Filter实现鉴权、访问日志记录,接口耗时记录等功能

    Spring Cloud Gateway架构图

    11464886-3d5c5bf5f3fc1340.png
    Spring Cloud Gateway架构图

    流程介绍:
    Gateway Client发送请求给Spring Cloud GatewayGateway Handler Mapping会判断请求的路径是否匹配路由的配置,如果匹配则会进入Gateway Web HandlerWeb Handler会读取路由上所配置的过滤器,然后将该请求交给过滤器去处理,最后转发到路由配置的微服务上

    • Gateway Client:泛指外部请求,例如浏览器、app、小程序等
    • Proxied Service:指的是被网关代理的微服务

    相关源码:

    • Gateway Handler Mapping:org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
    • Gateway Web Handler:org.springframework.cloud.gateway.handler.FilteringWebHandler

    创建Spring Cloud Gateway项目

    这里使用IDEA的Spring Initializr进行项目的创建,到选择依赖这一步勾选gateway依赖,如下图:


    11464886-538c2d6eac19d56b.png

    网关组件一般都配合服务发现组件使用,我这里使用Nacos作为服务发现组件,具体的依赖如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- Nacos Client -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <!--整合Spring Cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--整合Spring Cloud Alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    然后编写配置文件内容如下:

    server:
      port: 8040
    spring:
      application:
        name: gateway
      cloud:
        nacos:
          discovery:
            # 指定nacos server的地址
            server-addr: 127.0.0.1:8848
        gateway:
          discovery:
            locator:
              # 让gateway通过服务发现组件找到其他的微服务,从而自动转发请求
              enabled: true
    
    # actuator相关配置
    management:
      endpoints:
        web:
          exposure:
            # 暴露所有监控端点
            include: '*'
      endpoint:
        health:
          # 总是显示健康检测详情
          show-details: always
    

    完成以上步骤后,我们来启动这个网关服务,进行一个简单的测试,看看是否能将请求正常地转发到指定的微服务上。此时有一个名为user-center的微服务,该微服务有一个按id获取用户信息的接口,接口路径为/users/{id}。若通过网关服务来访问这个接口,要如何做呢?很简单,gateway配合服务发现组件使用时,会有一个默认的转发规则,如下:

    • ${GATEWAY_URL}/{微服务名称}/{接口路径}
      所以按该规则得出来的具体url为:localhost:8040/user-center/users/{id},访问结果如下:
      11464886-a9fc844aa76d5e74.png

    从测试结果可以看到,gateway可以根据url上的微服务名称将访问请求转发到该微服务上。
    以上这种是Gateway最简单的使用方式,但通常在实际开发中,可能不希望使用默认的转发规则,因为这种方式不太灵活,例如一些服务接口是存在版本划分的,需要根据不同版本的访问路径转发到不同版本的微服务上。此时就需要自定义转发路由,实际上在第一小节的时候就已经给出过配置示例了。修改配置如下:

    spring:
      cloud:
        gateway:
          routes:
          - id: user-center  # 唯一标识,通常使用服务id
            uri: lb://user-center  # 目标URL,lb代表从注册中心获取服务
            predicates:
            # Predicate集合
              - Path=/zj/cloud/v1/user-center/**  # 匹配转发路径
            filters:
            # Filter集合
              - StripPrefix=4  # 从第几级开始转发,数字从0开始
    

    自定义路由的注意事项:

    • predicates配置项必须有,且必须配置一个及以上的Predicate,但不一定非要配置Path,可以配置其他的Predicate,例如After、Before等,此时Path的默认值为/**

    重启项目,此时访问的url为:localhost:8040/zj/cloud/v1/user-center/users/{id},访问结果如下:


    11464886-ca4886949111025f.png

    路由配置的两种形式

    Spring Cloud Gateway的路由配置有两种形式,分别是路由到指定的URL以及路由到指定的微服务。在这两种形式中,均支持访问路径的通配及精确匹配,在之前的示例中我们只使用了通配。这里将给出具体的配置示例,以此直观的了解这两种形式及不同匹配方式在配置上的区别。

    • 路由到指定的URL
      通配,使用通配符/**进行匹配,示例:

      spring:
        cloud:
          gateway:
            routes:
              - id: test_route  # 路由的唯一标识
                uri: http://www.xxx.com
                predicates:
                  # 使用通配符匹配
                  - Path=/**
      

      该配置使访问 GATEWAY_URL/** 时会转发到 http://www.xxx.com/
      精确匹配,配置具体的接口路径即可,示例:

      spring:
        cloud:
          gateway:
            routes:
              - id: test_route  # 路由的唯一标识
                uri: http://www.xxx.com/user/order/detail
                predicates:
                  # 指定具体的路径进行匹配
                  - Path=/user/order/detail
      

      该配置使访问 GATEWAY_URL/user/order/detail 时会转发到 ttp://www.xxx.com/user/order/detail

    • 路由到指定的微服务
      通配,示例:

      spring:
        cloud:
          gateway:
            routes:
              - id: user-center  # 路由的唯一标识,这种形式下通常是微服务名称
                uri: lb://user-center  # lb代表从注册中心获取服务
                predicates:
                  # 使用通配符匹配
                  - Path=/**
      

      该配置使访问 GATEWAY_URL/** 时会转发到 user-center微服务的/**
      精确匹配,示例:

      spring:
        cloud:
          gateway:
            routes:
              - id: user-center  # 路由的唯一标识,这种形式下通常是微服务名称
                uri: lb://user-center/users/info  # lb代表从注册中心获取服务
                predicates:
                  # 指定具体的路径进行匹配
                  - Path=/users/info
      

      该配置使访问 GATEWAY_URL/users/info 时会转发到 user-center微服务的/users/info

    路由谓词工厂

    前面提到过谓词是路由的判断条件,而路由谓词工厂就是作用到指定路由上的一堆谓词判断条件。在之前的示例里,我们就已经使用过路由谓词工厂了,就是自定义转发路径时所配置的Path。

    内置的路由谓词工厂

    Spring Cloud Gateway内置了众多路由谓词工厂,这些路由谓词工厂为路由匹配的判断提供了有力的支持,而我们之前所使用的Path就是内置的路由谓词工厂之一,用于判断当前访问的接口路径是否与该路由所配置的路径相匹配,若匹配则进行转发。由于Gateway内置的路由谓词工厂比较多,篇幅有限就不在本文中介绍了,可以参考另一篇文章:

    自定义路由谓词工厂

    现在我们已经知道Spring Cloud Gateway内置了一系列的路由谓词工厂,但如果这些内置的路由谓词工厂不能满足业务需求的话,我们可以自定义路由谓词工厂来实现特定的需求。例如有某个服务限制用户只允许在09:00 - 17:00这个时间段内才可以访问,内置的路由谓词工厂是无法满足这个需求的,所以此时我们就需要自定义能够实现该需求的路由谓词工厂。

    首先定义一个配置类,用于承载时间段的配置参数:

    @Data
    public class TimeBetweenConfig {
        /**
         * 开始时间
         */
        private LocalTime start;
    
        /**
         * 结束时间
         */
        private LocalTime end;
    }
    

    然后定义一个路由谓词工厂,具体代码如下:

    import com.zj.node.gateway.config.TimeBetweenConfig;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    
    import java.time.LocalTime;
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
    
    /**
     * 路由谓词工厂必须以RoutePredicateFactory结尾,
     * 这是Spring Cloud Gateway的约定
     **/
    @Slf4j
    @Component
    public class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenConfig> {
    
        public TimeBetweenRoutePredicateFactory() {
            super(TimeBetweenConfig.class);
        }
    
        /**
         * 实现谓词判断的方法
         */
        @Override
        public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {
            return exchange -> {
                LocalTime start = config.getStart();
                LocalTime end = config.getEnd();
    
                // 判断当前时间是否为允许访问的时间段内
                LocalTime now = LocalTime.now();
                return now.isAfter(start) && now.isBefore(end);
            };
        }
    
        /**
         * 控制配置类(TimeBetweenConfig)属性和配置文件中配置项(TimeBetween)的映射关系
         */
        @Override
        public List<String> shortcutFieldOrder() {
            /*
             * 例如我们的配置项是:TimeBetween=上午9:00, 下午5:00
             * 那么按照顺序,start对应的是上午9:00;end对应的是下午5:00
             **/
            return Arrays.asList("start", "end");
        }
    }
    

    最后需要在配置文件中启用该路由谓词工厂,并且需要禁止gateway通过服务发现组件转发请求到其他的微服务,修改Gateway相关配置如下:

    spring:
      cloud:
        gateway:
          discovery:
            locator:
              # 禁止gateway通过服务发现组件转发请求到其他的微服务
              enabled: false
          routes:
            - id: user-center
              # 目标URL,lb代表从注册中心获取服务
              uri: lb://user-center
              predicates:
                # 注意名称必须为路由谓词工厂类名的前缀,参数为允许访问的时间段
                - TimeBetween=上午9:00,下午5:00
    

    可以看到这里主要是配置了我们自定义的路由谓词工厂类名的前缀以及允许访问的时间段,这个时间格式不是随便配置的,而是Spring Cloud Gateway的默认时间格式,相关源码如下:

    • org.springframework.format.support.DefaultFormattingConversionService#addDefaultFormatters
      时间格式是可以注册的,关于时间格式注册的相关源码如下:
    • org.springframework.format.datetime.standard.DateTimeFormatterRegistrar#registerFormatters

    另外,这里之所以要禁止gateway通过服务发现组件转发请求到其他的微服务,是因为开启该配置项的话会导致我们自定义的路由谓词工厂不生效。不生效也是有原因的,开启该配置项会令Gateway优先将请求按照该配置项进行转发,那么我们自定义的路由就不会生效。

    到此为止我们就实现了一个自定义路由谓词工厂,若此时不在允许的访问时间段内,访问就会报404,如下:


    11464886-1e417b53292931a6.png

    过滤器工厂

    前面提到了过滤器可以为请求和响应添加一些业务逻辑或者修改请求和响应对象等,适当地使用过滤器可以让我们的工作事半功倍,而本小节将要介绍的过滤器工厂就是用来创建过滤器的。在此之前我们已经学习过路由谓词工厂了,而过滤器工厂与路由谓词工厂在使用上是类似的,只不过实现的功能不一样。

    内置的过滤器工厂

    同样的Spring Cloud Gateway内置了非常多的过滤器工厂,有二十多个。通过这些内置的过滤器工厂就已经可以灵活且方便地处理请求和响应数据,由于Gateway内置的过滤器工厂实在太多,而篇幅有限就不在本文中介绍了,可以参考另一篇文章:

    自定义过滤器工厂

    若Spring Cloud Gateway内置的过滤器工厂无法满足我们的业务需求,那么此时就需要自定义自己的过滤器工厂以实现特定功能。所谓过滤器工厂实际上就是用于创建过滤器实例的,而创建的过滤器实例都实现于GatewayFilter接口。

    过滤器的生命周期:

    • Gateway以转发请求为边界,所以其生命周期只包含pre和post:
      • pre:Gateway转发请求之前
      • post:Gateway转发请求之后

    自定义过滤器工厂的方式:

    1. 继承AbstractGatewayFilterFactory,参考源码:org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory。使用该方式实现的过滤器工厂的配置形式如下:
    spring:
    cloud:
    gateway:
      routes:
        filters:
        # 过滤器工厂的名称
          - name: RequestSize
          # 该过滤器工厂的参数
          args:
            maxSize: 500000
    
    1. 继承AbstractNameValueGatewayFilterFactory,参考源码:org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory。使用该方式实现的过滤器工厂的配置形式如下:
    spring:
    cloud:
    gateway:
      routes:
        filters:
          # 过滤器工厂的名称及参数以name-value的形式配置
          - AddRequestHeader=S-Header, Bar
    

    注:AbstractNameValueGatewayFilterFactory继承了AbstractGatewayFilterFactory,所以实际上第二种方式是第一种方式的简化
    核心API:

    • exchange.getRequest().mutate().xxx:修改request
    • exchange.mutate().xxx:修改exchange
    • chain.filter(exchange):传递给下一个过滤器处理
    • exchange.getResponse():获取响应对象
      注:这里的exchange实际类型为ServerWebExchange,chain实际类型为atewayFilter

    最后我们来实际动手编写一个自定义过滤器工厂,需求是记录访问日志,这里为了简单起见采用第二种方式实现,具体代码如下:

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    
    /**
     * 过滤器工厂必须以GatewayFilterFactory结尾,
     * 这是Spring Cloud Gateway的约定
     *
     **/
    @Slf4j
    @Component
    public class PreLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    
        @Override
        public GatewayFilter apply(NameValueConfig config) {
            // 使用lambda表达式来创建GatewayFilter的实例,实际就是匿名内部类的简写
            return (exchange, chain) -> {
                // 通过config获取配置的参数
                log.info("配置参数:{}, {}", config.getName(), config.getValue());
    
                // 修改request,可以添加一些header什么的
                ServerHttpRequest modifiedRequest = exchange.getRequest()
                        .mutate()
                        .header("X-GatewayHeader","A","B")
                        .build();
    
                // 打印访问的接口地址
                String path = modifiedRequest.getURI().getPath();
                log.info("访问的接口为:{}", path);
    
                // 修改exchange
                ServerWebExchange modifiedExchange = exchange.mutate()
                        .request(modifiedRequest).build();
    
                // 传递给下一个过滤器处理
                return chain.filter(modifiedExchange);
            };
        }
    }
    

    最后需要添加相关配置以启用这个过滤器工厂,如下:

    spring:
      cloud:
        gateway:
          routes:
            - id: user-center
              uri: lb://user-center
              predicates:
                - TimeBetween=上午9:00,下午5:00
              filters:
                # 名称必须为过滤器工厂类名的前缀,并且参数只能有两个,因为NameValueConfig里只定义了两个属性
                - PreLog=testName,testValue
    

    启动项目,访问user-center的接口

    全局过滤器

    现在我们已经知道前面所介绍的过滤器工厂实际用于创建GatewayFilter实例,并且这些GatewayFilter实例仅作用于指定的路由上,那么有没有可以作用于全部路由上的过滤器呢?答案是有的,这就是本小节将要介绍的全局过滤器。Spring Cloud Gateway默认就内置了许多全局过滤器,本文仅介绍如何自定义全局过滤器,关于Gateway内置的过滤器可以参考另一篇文章:

    自定义全局过滤需要实现GlobalFilter 接口,该接口和 GatewayFilter 有一样的方法定义,只不过 GlobalFilter 的实例会作用于所有的路由。

    Tips:

    官方声明:GlobalFilter的接口定义以及用法在未来的版本可能会发生变化。
    个人判断:GlobalFilter可用于生产;如果有自定义GlobalFilter的需求,理论上也可放心使用。因为未来即使接口定义以及使用方式发生变化,理应也是平滑过渡的(比如Zuul的Fallback,原先叫ZuulFallbackProvider,后来改叫FallbackProvider,中间就有段时间新旧使用方式都支持,后面才逐步废弃老的使用方式)。

    接下来我们自定义一个全局过滤器,需求是打印访问的接口路径以及打印该接口的访问耗时。具体代码如下:

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    /**
     * 自定义全局过滤器
     *
     **/
    @Slf4j
    public class MyGlobalFilter implements GlobalFilter {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            String path = exchange.getRequest().getURI().getPath();
            log.info("[MyGlobalFilter] 访问的接口:{}", path);
    
            long start = System.currentTimeMillis();
            return chain.filter(exchange)
                    // then的内容会在过滤器返回的时候执行,即最后执行
                    .then(Mono.fromRunnable(() ->
                            log.info("[ {} ] 接口的访问耗时:{} /ms", 
                            path, System.currentTimeMillis() - start))
                    );
        }
    }
    

    最后需要使该全局过滤器生效,方法有很多种,可以直接在该类上加@Component注解,也可以通过代码配置(@Bean),还有其他的一些方式。这里个人比较倾向于使用一个专门的配置类去实例化这些全局过滤器并交给Spring容器管理。代码如下:

    import com.zj.node.gateway.filter.MyGlobalFilter;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    
    @Slf4j
    @Configuration
    public class FilterConfig {
    
        @Bean
        // 该注解用于指定过滤器的执行顺序,数字越小越优先执行
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public GlobalFilter myGlobalFilter(){
            log.info("create myGlobalFilter...");
            return new MyGlobalFilter();
        }
    }
    

    启动项目,看看我们自定义的全局过滤器是否已生效。

    参考原文:https://blog.51cto.com/zero01/2430424

    展开全文
  • 计算机网络体系几样通信设备或者说网络名词出现的频率相当的高,它们是:中继器、集线器、网桥、交换机、路由器和网关。其实,弄清楚这几计算机网络的名词并不困难,如果能以计算机网络层次的概念给它们划清...
  • 个网络用四个路由器(每一个路由器两个端口)互连起来。能否改变这种连接方法,使用一个具有五个端口的路由器将这五个网络互连起来? 问题4-9:当运行PING 127.0.0.1时,这个IP数据报将发送给谁? 问题4-10:...
  • 个网络用四个路由器(每一个路由器两个端口)互连起来。能否改变这种连接方法,使用一个具有五个端口的路由器将这五个网络互连起来? 问题6-9:当运行PING 127.0.0.1时,这个IP数据报将发送给谁? 问题6-10:...
  • 计算机网络复习题

    2014-12-29 19:01:35
    (2)在面向连接的TCP协议,TCP包中有一个Window size 字段,接收方可以通过该字段告诉发送方,自己还有多少个接收缓冲区,极端情况下,当接收方不能再接收数据时,把该字段设置为0,从而发送方可以根据该字段的值...
  • 你的路由器缺省网关吗?如果,指向了哪里?在病毒爆发的时候把缺省网关指向另外台路由器是很危险的(除非你想搞瘫这台路由器)。在一些企业网里往往仅指出网内地址段的路由,而不加缺省路由,那么就把缺省路由...
  • 多媒体教室

    2013-06-14 08:10:31
    如果网络中没有服务器或服务器上没有安装 DHCP 服务,此时网络中所有计算机的网卡所绑定的 TCP/IP 协议的设置上必须指定一个固定的 IP 地址。具体的设置请咨询您所使用的网络的网络管理员。 设置参考: 1、打开控制...
  • 服务网关和Zuul 为什么要有服务网关: 我们都知道在微服务架构,...我们已经知道,在微服务架构,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N微服务的...
  • Eclipse 是一个独立于域的后端解决方案,用于将软件更新部署到受约束的边缘设备以及连接到基于IP的网络基础结构的更强大的控制器和网关。 建立: 码头工人: 文献资料 请参阅 联系我们 对hawkBit疑问吗? 检查 ...
  • 微服务下一个系统被拆分为多个服务,但是像 安全认证,流量控制,日志,监控等功能是每个服务都需要的,没有网关的话,我们就需要在每个服务单独实现,这使得我们做了很多重复的事情并且没有一个全局的视图来统一...
  • 以太网交换机

    2018-05-01 06:53:59
    将internet的连接共享第一个(允许其他网络通过此计算机的internet连接来连接)前面勾选,确定就可以了 这样还不行,接下来在第一台机器上打开网上邻居属性 -设置家庭或小型办公网络-然后下一步,在连接方法时选择第二个...
  • Linux从入门到精通

    2010-04-25 19:58:09
    E.8.10 我的计算机有一个NeoMagic 显示卡芯片组, 我可以用X吗? E.8.11 我从4.1(或更早)升级, 现在启动X时, 机器在一个灰色屏幕上吊死. E.8.12 当我运行netscape, 色彩似乎不对, 或者得到关于色彩的出错信息. E....
  • 常用的DOS命令

    2012-12-18 17:23:00
    ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:网络上的机器都唯一确定的IP地址,我们给目标IP地址发送一个数据包,对方就要返回一个同样大小的数据包,根据返回的数据包我们可以确定目标主机的...
  • 《Linux从入门到精通》

    热门讨论 2008-09-04 17:05:49
    E.8.10 我的计算机有一个NeoMagic 显示卡芯片组, 我可以用X吗? E.8.11 我从4.1(或更早)升级, 现在启动X时, 机器在一个灰色屏幕上吊死. E.8.12 当我运行netscape, 色彩似乎不对, 或者得到关于色彩的出错信息. E....
  • 可以覆盖大部分计网的知识点,可以从 DNS 解析到 HTTP、TCP/IP协议、物理层协议,一直到浏览器渲染页面,你技术功底有多深你就可以聊多深。希望大家学完了也能试着回答一下这问题。 推荐几本倍受好评的书: ...
  • SSO(单点登录) :SSO(Single Sign On) 即单点登录说的是用户登陆多个子系统的其中一个就有权访问与其相关的其他系统。举个例子我们在登陆了京东金融之后,我们同时也成功登陆京东的京东超市、京东家电等子系统。相关...
  • 比如数据量太大之后,往往需要对进行对数据进行分库分表,分库分表后需要有一个唯一 ID 来标识一条数据或消息,数据库的自增 ID 显然不能满足需求。相关阅读:为什么要分布式 id ?分布式 id 生成方案哪些? ...
  • 比如数据量太大之后,往往需要对进行对数据进行分库分表,分库分表后需要有一个唯一 ID 来标识一条数据或消息,数据库的自增 ID 显然不能满足需求。相关阅读:为什么要分布式 id ?分布式 id 生成方案哪些? ...
  • 让默认的就可以了,但是超频玩者是肯定不会放过任何可以提高性能的东西的,所以如果你想在这里让你的电脑提升一点性能的话,就必须慢慢试验,选择一个适当的参数才能让你的计算机达到性能和稳定的最佳状态!...
  • windows实用dos命令大全

    2010-12-10 21:27:35
    (2)PATH命令的路径,若两条以上,各路径之间以一个分号“;”隔开;  (3)PATH命令三种使用方法:  PATH[盘符1:][路径1][盘符2:][路径2]…(设定可执行文件的搜索路径) PATH:(取消所有路径)  ...
  •  硬盘中有一个很宠大的数据交换文件,它是系统预留给虚拟内存作暂存的地方,很应用程序都经常会使用到,所以系统需要经常对主存储器作大量的数据存取,因此存取这个档案的速度便构成影响计算机快慢的非常重要因素...
  • 如果有多引导系统的计算机,必须保证是在包含 Windows 的驱动器上使用该命令。 Diskpart  创建和删除硬盘驱动器上的分区。diskpart 命令仅在使用故障恢复控制台时才可用。  diskpart [ /add |/delete] [device_...

空空如也

空空如也

1 2
收藏数 26
精华内容 10
关键字:

一个网络中可以有多个网关吗