成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

16 圖 | 深入理解 Spring Cloud Gateway 的原理

開發 前端
在 PassJava 項目中,我用到了 Spring Cloud Gateway 作為 API 網關,客戶端的所有的請求都是先經過網關,然后再轉發到會員微服務、題目微服務等。

你好,我是悟空。

本篇給大家帶來的是微服務框架中非常重要的一個組件:API 網關。

圖片

前言

在 PassJava 項目中,我用到了 Spring Cloud Gateway 作為 API 網關,客戶端的所有的請求都是先經過網關,然后再轉發到會員微服務、題目微服務等。

比如 API 網關和會員微服務對應的訪問地址如下:

API 網關地址:http://localhost:8060

會員微服務地址:http://localhost:14000

客戶端請求都是訪問的 API 網關,然后網關轉發到會員微服務,客戶端無需知道會員微服務的地址。

本篇將會以 PassJava 作為案例進行講解。

PassJava 開源地址:https://github.com/Jackson0714/PassJava-Platform

為什么需要 API 網關

在 SpringBoot 單體架構中,一般只有一個后端服務,如下圖所示:

圖片

單體架構訪問示例圖

但是在 SpringCloud 微服務架構中,往往有多個微服務,這些微服務可能部署在不同的機器上,而且一個微服務可能會擴容成多個相同的微服務,組成微服務集群。

圖片

微服務架構訪問示例圖

這種情況下,會存在如下問題:

  • 如果需要添加鑒權功能,則需要對每個微服務進行改造。
  • 如果需要對流量進行控制,則需要對每個微服務進行改造。
  • 跨域問題,需要對每個微服務進行改造。
  • 存在安全問題,每個微服務需要暴露自己的 Endpoint 給客戶端。Endpoint 就是服務的訪問地址 + 端口。比如下面的地址:
http://order.passjava.cn:8000
  • 灰度發布、動態路由需要對每個微服務進行改造。

這個問題的痛點是各個微服務都是一個入口,有沒有辦法統一入口呢?

解決這個問題的方式就是在客戶端和服務器之間加個中間商就好了呀,只有中間商一個入口,這個中間商就是網關。

還有一個細節問題:多個微服務之間是如何通信的?這就要用到遠程調用組件了,比如 OpenFeign。但是服務之間的調用是需要知道對方的 Endpoint 的,如果一個服務有多個微服務,就需要通過負載均衡組件進行流量分發。那微服務之間不就暴露 Endpoint 了嗎?這個沒有問題,畢竟只是后端服務知道,外界是不知道的。

圖片

為了幫助大家更容易理解網關的作用,這里有個網關、客戶端、微服務的三方通話。

網關對話

網關:客戶端你好,你現在可以只跟我通信了,我可以將你本來想發給微服務的流量進行轉發,微服務處理完之后,將結果返回給我,我再給你。

客戶端:你沒有賺差價吧?

API 網關:我可能會加些請求頭、做下認證、鑒權、限流等。

客戶端:微服務不是自己可以做嗎?

API 網關:但是每個微服務都得自己加,這就很麻煩了,都交給我就好了。

微服務:網關你好,你會為我保密我的地址對嗎?

API 網關:當然,我給客戶端看的是我自己的地址,客戶端不需要知道你的地址,只需要知道你的 API 是哪個就行,剩下的交給我來轉發給你。

API 網關選型對比

業界比較出名的網關:Spring Cloud Gateway、Netflix Zuul、Nginx、Kong、Alibaba Tengine。

作為 Spring Cloud 全家桶中的一款組件,當然選擇 Spring Cloud Gateway 了。

最開始 Spring Cloud 推薦的網關是 Netflix Zuul 1.x,但是停止維護了,后來又有 Zuul 2.0,但是因為開發延期比較嚴重,Spring Cloud 官方自己開發了 Spring Cloud Gateway 網關組件,用于代替 Zuul 網關。

所以本篇我們只會講解 Spring Cloud Gateway 網關組件。

Spring Cloud Gateway 的工作流程

Gateway 的工作流程如下圖所示:

圖片

① 路由判斷;客戶端的請求到達網關后,先經過 Gateway Handler Mapping 處理,這里面會做斷言(Predicate)判斷,看下符合哪個路由規則,這個路由映射后端的某個服務。

② 請求過濾:然后請求到達 Gateway Web Handler,這里面有很多過濾器,組成過濾器鏈(Filter Chain),這些過濾器可以對請求進行攔截和修改,比如添加請求頭、參數校驗等等,有點像凈化污水。然后將請求轉發到實際的后端服務。這些過濾器邏輯上可以稱作 Pre-Filters,Pre 可以理解為“在...之前”。

③ 服務處理:后端服務會對請求進行處理。

④ 響應過濾:后端處理完結果后,返回給 Gateway 的過濾器再次做處理,邏輯上可以稱作 Post-Filters,Post 可以理解為“在...之后”。

⑤ 響應返回:響應經過過濾處理后,返回給客戶端。

小結:客戶端的請求先通過匹配規則找到合適的路由,就能映射到具體的服務。然后請求經過過濾器處理后轉發給具體的服務,服務處理后,再次經過過濾器處理,最后返回給客戶端。

Spring Cloud Gateway 的斷言

斷言(Predicate)這個詞聽起來極其深奧,它是一種編程術語,我們生活中根本就不會用它。說白了它就是對一個表達式進行 if 判斷,結果為真或假,如果為真則做這件事,否則做那件事。

在 Gateway 中,如果客戶端發送的請求滿足了斷言的條件,則映射到指定的路由器,就能轉發到指定的服務上進行處理。

斷言配置的示例如下,配置了兩個路由規則,有一個 predicates 斷言配置,當請求 url 中包含 api/thirdparty,就匹配到了第一個路由 route_thirdparty。(代碼示例來自我的開源項目 PassJava)。

圖片

圖片斷言配置

接下來我們看下 Route 路由和 Predicate 斷言的對應關系:

圖片

斷言和路由的對應關系原理圖

  • 一對多:一個路由規則可以包含多個斷言。如上圖中路由 Route1 配置了三個斷言 Predicate。
  • 同時滿足:如果一個路由規則中有多個斷言,則需要同時滿足才能匹配。如上圖中路由 Route2 配置了兩個斷言,客戶端發送的請求必須同時滿足這兩個斷言,才能匹配路由 Route2。
  • 第一個匹配成功:如果一個請求可以匹配多個路由,則映射第一個匹配成功的路由。如上圖所示,客戶端發送的請求滿足 Route3 和 Route4 的斷言,但是 Route3 的配置在配置文件中靠前,所以只會匹配 Route3。

常見的 Predicate 斷言配置如下所示,假設匹配路由成功后,轉發到 http://localhost:9001

圖片

圖片常見的 Predicate 斷言配置

代碼演示

下面演示 Gateway 中通過斷言來匹配路由的例子。

  • 新建一個 Maven 工程,引入 Gateway 依賴。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
  • 新建 application.yml 文件,添加 Gateway 的路由規則。
spring:
cloud:
gateway:
routes:
- id: route_qq
uri: http://www.qq.com
predicates:
- Query=url,qq
- id: route_baidu
uri: http://www.baidu.com
predicates:
- Query=url,baidu
server:
port: 8060

第一條路由規則:斷言為 Query=url,qq,表示當請求路徑中包含 url=qq,則跳轉到http://www.qq.com

第二條路由規則:當請求路徑中包含 url=baidu,則跳轉到http://www.baidu.com

Spring Cloud Gateway 動態路由

在微服務架構中,我們不會直接通過 IP + 端口的方式訪問微服務,而是通過服務名的方式來訪問。如下圖所示,微服務中加入了注冊中心,多個微服務將自己注冊到了注冊中心,這樣注冊中心就保存了服務名和 IP+端口的映射關系。

圖片

圖片微服務注冊到注冊中心

接下來我們來看下加入 Gateway 后,請求是如何進行轉發的。

客戶端先將請求發送給 Nginx,然后轉發到網關,網關經過斷言匹配到一個路由后,將請求轉發給指定 uri,這個 uri 可以配置成 微服務的名字,比如 passjava-member。

那么這個服務名具體要轉發到哪個 IP 地址和端口上呢?這個就依賴注冊中心的注冊表了,Gateway 從注冊中心拉取注冊表,就能知道服務名對應具體的 IP + 端口,如果一個服務部署了多臺機器,則還可以通過負載均衡進行請求的轉發。原理如下圖所示:

圖片

網關+注冊中心

對應的配置為 uri 字段如下所示:

圖片

圖片uri: lb://passjava-question,表示將請求轉發給 passjava-question 微服務,且支持負載均衡。lb 是 loadbalance(負載均衡) 單詞的縮寫。

那什么叫動態路由呢?

當 passjava-question 服務添加一個微服務,或者 IP 地址更換了,Gateway 都是可以感知到的,但是配置是不需要更新的。這里的動態指的是微服務的集群個數、IP 和端口是動態可變的。

代碼示例

案例:調用 OSS 第三方服務,上傳文件到 OSS。(基于 PassJava 項目)

前提:前端頁面配置的統一訪問路徑是網關的地址:http://localhost:8060/api/,OSS 服務對應的地址是http://localhost:14000。

期望結果:將前端請求

http://localhost:8060/api/thirdparty/v1/admin/oss/getPolicy

轉發到 OSS 服務。

http://localhost:14000/thirdparty/v1/admin/oss/getPolicy

配置網關:

spring:
cloud:
gateway:
routes:
- id: route_thirdparty # 第三方微服務路由規則
uri: lb://passjava-thirdparty # 負載均衡,將請求轉發到注冊中心注冊的 passjava-thirdparty 服務
predicates: # 斷言
- Path=/api/thirdparty/** # 如果前端請求路徑包含 api/thirdparty,則應用這條路由規則
filters: #過濾器
- RewritePath=/api/(?<segment>.*),/$\{segment} # 將跳轉路徑中包含的api替換成空

測試上傳文件成功。

圖片

圖片

接下來我們看下 Gateway 非常重要且核心的功能:過濾器。

Spring Cloud Gateway 的過濾器

網關,顧名思義,就是網絡中的一道關卡,可以統一對請求和響應進行一些操作。

過濾器 Filter 的分類

過濾器 Filter 按照請求和響應可以分為兩種:Pre 類型和 Post 類型。

Pre 類型:在請求被轉發到微服務之前,對請求進行攔截和修改,例如參數校驗、權限校驗、流量監控、日志輸出以及協議轉換等操作。

Post 類型:微服務處理完請求后,返回響應給網關,網關可以再次進行處理,例如修改響應內容或響應頭、日志輸出、流量監控等。

另外一種分類是按照過濾器 Filter 作用的范圍進行劃分:

GlobalFilter:全局過濾器,應用在所有路由上的過濾器。

局部過濾器

GatewayFilter:局部過濾器,應用在單個路由或一組路由上的過濾器。標紅色表示比較常用的過濾器。

整理了一份 27 種自帶的 GatwayFilter 過濾器。

圖片

具體怎么用呢,這里有個示例,如果 URL 匹配成功,則去掉 URL 中的 “api”。

filters: #過濾器
- RewritePath=/api/(?<segment>.*),/$\{segment} # 將跳轉路徑中包含的 “api” 替換成空

當然我們也可以自定義過濾器,本篇不做展開。

全局過濾器

整理了一份全局過濾器的表格,具體用法可以參照官方文檔。

官方文檔:https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#_global_filters

圖片

全局過濾器最常見的用法是進行負載均衡。配置如下所示:

spring:
cloud:
gateway:
routes:
- id: route_member # 第三方微服務路由規則
uri: lb://passjava-member # 負載均衡,將請求轉發到注冊中心注冊的 passjava-member 服務
predicates: # 斷言
- Path=/api/member/** # 如果前端請求路徑包含 api/member,則應用這條路由規則
filters: #過濾器
- RewritePath=/api/(?<segment>.*),/$\{segment} # 將跳轉路徑中包含的api替換成空

這里有個關鍵字 lb,用到了全局過濾器 LoadBalancerClientFilter,當匹配到這個路由后,會將請求轉發到 passjava-member 服務,且支持負載均衡轉發,也就是先將 passjava-member 解析成實際的微服務的 host 和 port,然后再轉發給實際的微服務。

實現簡單的 token 認證

在用 Gateway 做登錄認證的時候,通常需要我們自定義一個過濾器做登錄認證。

比如客戶端登錄時,將用戶名和密碼發送給網關,網關轉發給認證服務器后,如果賬號密碼正確,則拿到一個 JWT token,然后客戶端再訪問應用服務時,先將請求發送給網關,網關統一做 JWT 認證,如果 JWT 符合條件,再將請求轉發給應用服務。

原理如下圖所示,紅色框框的部分就是待會我要演示的部分。

圖片

案例演示

下面做一個簡單的認證實例。客戶端攜帶 token 訪問 member 服務,網關會先校驗 token 的合法性,驗證規則如下:

當請求的 header 中包含 token,且 token = admin,則認證通過。

當驗證通過后,就會將請求轉發給 member 服務。

代碼示例

先定義一個全局過濾器,驗證 token 的合法性。

@Component
public class GlobalLoginFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request= exchange.getRequest();
String token = request.getHeaders().getFirst("token");
if(!StringUtils.isEmpty(token)){
if("admin".equals(token)){
return chain.filter(exchange);
}
}
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}

@Override
public int getOrder() {
return 0;
}
}
  • 測試 token 不正確的場景。

先測試在 header 中添加 token=123,響應結果為 401  Unauthorized,沒有權限。

圖片

  • 測試 token 正確的場景。

然后測試在 header 中添加 token=admin,正常返回響應數據。


圖片


責任編輯:武曉燕 來源: 悟空聊架構
相關推薦

2021-03-10 10:55:51

SpringJava代碼

2022-08-22 08:04:25

Spring事務Atomicity

2022-01-14 12:28:18

架構OpenFeign遠程

2020-08-10 18:03:54

Cache存儲器CPU

2024-04-15 00:00:00

技術Attention架構

2024-03-12 00:00:00

Sora技術數據

2022-11-04 09:43:05

Java線程

2024-11-01 08:57:07

2022-09-05 08:39:04

kubernetesk8s

2023-06-07 15:34:21

架構層次結構

2020-03-18 13:40:03

Spring事數據庫代碼

2020-11-04 15:35:13

Golang內存程序員

2020-03-17 08:36:22

數據庫存儲Mysql

2019-07-01 13:34:22

vue系統數據

2022-09-05 22:22:00

Stream操作對象

2023-10-13 13:30:00

MySQL鎖機制

2021-05-27 11:30:54

SynchronizeJava代碼

2020-03-26 16:40:07

MySQL索引數據庫

2023-09-19 22:47:39

Java內存

2022-09-26 08:01:31

線程LIFO操作方式
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区国产 | 日本黄色免费大片 | 欧美看片 | 亚洲国产精品视频一区 | 亚洲国产精品久久久 | 国产成人精品免高潮在线观看 | 国产成人综合在线 | 日本特黄a级高清免费大片 成年人黄色小视频 | 亚洲国产成人av好男人在线观看 | 日韩一区二区三区在线观看 | 欧美黄色性生活视频 | 一级毛片视频在线 | 久久精品亚洲一区 | 成人a在线观看 | 色婷婷一区二区三区四区 | 精品国产一区二区三区久久狼黑人 | 中文字幕日韩欧美一区二区三区 | 亚洲精品一区中文字幕乱码 | 天天看天天操 | 中文字幕成人av | 国产一区二区三区四区在线观看 | 精品欧美色视频网站在线观看 | 国产午夜三级一区二区三 | 午夜影院在线播放 | av毛片| 国产乱人伦精品一区二区 | 国产视频福利一区 | 伊人网在线播放 | 日日干夜夜操天天操 | 一区二区三区在线播放视频 | 日韩欧美一级片 | 国产激情片在线观看 | 国产精品毛片一区二区在线看 | 精品视频免费在线 | 欧美做暖暖视频 | 国产aa| 国产成人精品免费视频大全最热 | 日韩在线免费视频 | 97超碰人人草 | 国产成人精品久久 | 蜜臀久久99精品久久久久久宅男 |