dw做的網(wǎng)站鏈接不會(huì)跳轉(zhuǎn)什么是搜索引擎優(yōu)化
一、路由斷言
- 路由斷言就是判斷路由轉(zhuǎn)發(fā)的規(guī)則
二、路由過(guò)濾器
1. 路由過(guò)濾器可以實(shí)現(xiàn)對(duì)網(wǎng)關(guān)請(qǐng)求的處理,可以使用 Gateway 提供的,也可以自定義過(guò)濾器
2. 路由過(guò)濾器 GatewayFilter(默認(rèn)不生效,只有配置到路由后才會(huì)生效):
-
只對(duì)一個(gè)路由生效,配置到 routes 下,和 predicates 同級(jí)
-
對(duì)所有路由生效:配置到 default-filters
3. 全局過(guò)濾器 GlobalFilter(所有路由都生效):聲明后自動(dòng)生效
三、網(wǎng)關(guān)請(qǐng)求處理流程
業(yè)務(wù)實(shí)戰(zhàn):如果要進(jìn)行用戶校驗(yàn),應(yīng)該在網(wǎng)關(guān)請(qǐng)求轉(zhuǎn)發(fā)之前先完成對(duì)用戶的校驗(yàn),判斷用戶是否有請(qǐng)求權(quán)限
網(wǎng)關(guān)請(qǐng)求轉(zhuǎn)發(fā):NettyRoutingFilter 的 PRE 階段
做法:
1. 在 NettyRoutingFilter 之前的過(guò)濾器鏈中自定義過(guò)濾器完成登錄校驗(yàn)
2. 在自定義過(guò)濾器 PRE 階段完成登錄校驗(yàn)(POST 階段請(qǐng)求已經(jīng)轉(zhuǎn)發(fā)了,不符合業(yè)務(wù):先登錄才能請(qǐng)求)
3. 網(wǎng)關(guān)中沒(méi)有業(yè)務(wù)邏輯,只是做路由轉(zhuǎn)發(fā),網(wǎng)關(guān)進(jìn)行登錄校驗(yàn)之后獲取用戶信息并沒(méi)有實(shí)際作用(除了校驗(yàn))
4. 網(wǎng)關(guān)將請(qǐng)求轉(zhuǎn)發(fā)到微服務(wù),微服務(wù)需要用戶信息!網(wǎng)關(guān)需要將用戶信息傳給微服務(wù)
5. 怎么傳?:網(wǎng)關(guān)將請(qǐng)求轉(zhuǎn)發(fā)到微服務(wù),其實(shí)就是發(fā)起了一次 HTTP 請(qǐng)求,可以將用戶信息保存到請(qǐng)求頭,微服務(wù)從請(qǐng)求頭中取出用戶信息,且不會(huì)對(duì)業(yè)務(wù)造成影響 ?
6. 微服務(wù)之間的調(diào)用怎么獲取用戶信息?:網(wǎng)關(guān)只將用戶信息傳遞給了一個(gè)微服務(wù)(cart-service),但是微服務(wù)之間會(huì)相互調(diào)用(trade-service 調(diào)用 cart-service)trade-service 并沒(méi)有用戶信息,cart-service 也不會(huì)自動(dòng)將用戶信息傳遞給調(diào)用它的微服務(wù)
- 可以使用將用戶信息保存到請(qǐng)求頭的方式在微服務(wù)之間傳遞用戶信息嗎
- 微服務(wù)之間的請(qǐng)求(OpenFeign)和網(wǎng)關(guān)與微服務(wù)之間(Spring Cloud Gateway 內(nèi)置的)的請(qǐng)求不同,實(shí)現(xiàn)方式有差別
?
四、網(wǎng)關(guān)統(tǒng)一實(shí)現(xiàn)用戶登錄校驗(yàn)(基于 JWT)
1. 自定義過(guò)濾器并控制過(guò)濾器的順序
-
路由過(guò)濾器GatewayFilter(默認(rèn)不生效,只有配置到路由后才會(huì)生效):
-
只對(duì)一個(gè)路由生效,配置到 routes 下,和 predicates 同級(jí)
-
對(duì)所有路由生效:配置到 default-filters
-
- ?全局過(guò)濾器 GlobalFilter(所有路由都生效):聲明后自動(dòng)生效
filter 方法解讀:
-
參數(shù) 1 ServerWebExchange exchange:網(wǎng)關(guān)內(nèi)部的上下文對(duì)象,保存網(wǎng)關(guān)內(nèi)部整個(gè)過(guò)濾器鏈的共享數(shù)據(jù),如 request、response、session 及 一些自定義的共享屬性,所有過(guò)濾器都可以從 exchange 中讀取 / 存儲(chǔ)共享數(shù)據(jù)
-
參數(shù) 2 GatewayFilterChain chain:過(guò)濾器鏈,當(dāng)前過(guò)濾器執(zhí)行完之后,通過(guò) chain 調(diào)用過(guò)濾器鏈中的下一個(gè)過(guò)濾器
網(wǎng)關(guān)采用的是非阻塞式的編程,利用 Mono 定義回調(diào)函數(shù),等之后請(qǐng)求轉(zhuǎn)發(fā)回來(lái)的返回結(jié)果有了再調(diào)用回調(diào)函數(shù)(過(guò)濾器中 POST 部分的邏輯),一般不用寫(xiě)回調(diào)
e.g 實(shí)際開(kāi)發(fā)中遇到的回調(diào):接口調(diào)用成功后統(tǒng)計(jì)接口調(diào)用次數(shù) + 1,就是要等到返回結(jié)果是 ok 的再去執(zhí)行調(diào)用次數(shù) + 1 的邏輯!
-
返回值 Mono<Void>:每個(gè)過(guò)濾器執(zhí)行完之后直接返回 Mono
自定義過(guò)濾器的優(yōu)先級(jí)比 NettyRoutingFilter 高即可,NettyRoutingFilter 的 order 值是 maxInt,優(yōu)先級(jí)最低
// 1. 實(shí)現(xiàn) GlobalFilter 接口中的 filter 方法
// 2. 實(shí)現(xiàn) Orderd 接口的 getOrder 方法,通過(guò) ORDER 控制過(guò)濾器優(yōu)先級(jí)
// 3. 放行(將 exchange 傳到下一個(gè)過(guò)濾器)
2. 在網(wǎng)關(guān)實(shí)現(xiàn)登錄校驗(yàn)
-
獲取請(qǐng)求頭
-
判斷請(qǐng)求路徑是否需要攔截(有些路徑不需要登錄也可以查看)
使用 Spring 提供的 AntPathMatcher 的 match() 方法來(lái)校驗(yàn)路徑是否匹配指定的路徑模式 pathPattern(/search/** 等路徑)
private final AntPathMatcher antPathMatcher = newAntPathMatcher();
-
獲取 token
-
校驗(yàn)并解析 token
-
攔截未登錄用戶
-
設(shè)置響應(yīng)狀態(tài)碼:未登錄 401
-
終止流程
-
3. 網(wǎng)關(guān)傳遞用戶信息給下游微服務(wù)
-
傳遞
-
使用上下文對(duì)象中修改請(qǐng)求的 API:mutate()
-
將構(gòu)造好的新的上下文對(duì)象傳給下一個(gè)過(guò)濾器
-
- 獲取:微服務(wù)中的很多業(yè)務(wù)都需要獲取用戶信息,將從請(qǐng)求頭中獲取用戶信息的邏輯寫(xiě)到攔截器中,統(tǒng)一獲取;可能會(huì)有很多個(gè)微服務(wù),寫(xiě)攔截器要在所有微服務(wù)里都寫(xiě)一遍?=> 寫(xiě)到公共模塊 common 其他微服務(wù)都引入這個(gè)模塊(依賴),就都有了攔截器的功能 ?
-
定義攔截器
-
實(shí)現(xiàn) HandlerInterceptor 接口其中的 preHandle() 方法,在 Controller 之前執(zhí)行
-
實(shí)現(xiàn) afterCompletion() 方法在 Controller 執(zhí)行完之后執(zhí)行,清楚 ThreadLocal 中的用戶信息
-
-
注冊(cè)攔截器:定義 SpringMVC 的配置類(lèi),實(shí)現(xiàn) WebMvcConfigurer 中的 addInterceptors()
-
掃描包:common 模塊和微服務(wù)模塊所在包不同,Spring 不會(huì)自動(dòng)掃描到配置類(lèi),需要自己配置,實(shí)現(xiàn) Spring 自動(dòng)裝配
-
保存到 ThreadLocal 中,其他業(yè)務(wù)從 ThreadLocal 取出用戶信息
-
注意?網(wǎng)關(guān)模塊不能使用 / 引用 SpringMVC 相關(guān)的類(lèi),Spring Cloud Gateway 的底層用的不是 SpringMVC,而是響應(yīng)式的 webflux
網(wǎng)關(guān)項(xiàng)目也引入了 common 模塊,但是 common 模塊中定義了 SpringMVC 的攔截器,微服務(wù)項(xiàng)目需要該攔截器,網(wǎng)關(guān)不需要該攔截器,如何次攔截器配置類(lèi)在有些情況(微服務(wù)模塊)生效,有些情況(網(wǎng)關(guān))不生效?
解決方法:讓 SpringMVC 的配置類(lèi)根據(jù)條件來(lái)加載,即判斷是否有 SpringMVC(網(wǎng)關(guān)和其他微服務(wù)項(xiàng)目的差別就是是否有 SpringMVC,可以根據(jù)是否有 SpringMVC 中的核心 API DispatcherServlet)
實(shí)現(xiàn):使用 Spring 的條件注解 @ConditionalOnClass(DispatcherServlet.class)
4.??微服務(wù)之間的信息傳遞(OpenFeign 傳遞用戶)
用戶信息是從 ThreadLocal 中取的,要先從請(qǐng)求頭中獲取用戶信息才能存到 ThreadLocal 中,而請(qǐng)求頭中的用戶信息是網(wǎng)關(guān)向微服務(wù)發(fā)起請(qǐng)求時(shí)添加的,但是微服務(wù)之間的是直接調(diào)用的,沒(méi)有經(jīng)過(guò)網(wǎng)關(guān),而是通過(guò) OpenFeign 的遠(yuǎn)程調(diào)用,如何修改 OpenFeign 發(fā)起的請(qǐng)求?
-
OpenFeign 中提供了一個(gè)攔截器接口 RequestInterceptor,所有由 OpenFeign 發(fā)起的請(qǐng)求(遠(yuǎn)程調(diào)用)都會(huì)先調(diào)用攔截器處理請(qǐng)求
-
其中的 RequestTemplate 類(lèi)中提供了一些方法(如 header())可以讓我們修改請(qǐng)求頭