1. 網(wǎng)關(guān)介紹
到現(xiàn)在,我們可以使用Nacos對不同的微服務(wù)進(jìn)行注冊并管理配置文件,也可以使用 Feign
對不同的微服務(wù)進(jìn)行訪問,但是,這種訪問是任何人都可以訪問的,這是不行的,訪問之間應(yīng)該有某種權(quán)限的控制,而且,如果所有允許的訪問都可以進(jìn)入,那么如果有一個時間訪問量太過巨大則會引起服務(wù)器出現(xiàn)問題,這就需要使得請求限流了,所以,我們需要使用一些工具來達(dá)到這些目的,這就是網(wǎng)關(guān)Gateway。
網(wǎng)關(guān)具體需要實(shí)現(xiàn)的功能包括:
- 對用戶請求做身份認(rèn)證、權(quán)限校驗(yàn)
- 將用戶請求路由到微服務(wù),并實(shí)現(xiàn)負(fù)載均衡
- 對用戶請求做限流
SpringCloud中網(wǎng)關(guān)的實(shí)現(xiàn)有兩種:
- gateway
- zuul
zuul是基于Servlet的實(shí)現(xiàn),屬于阻塞式編程。而SpringCloudGateway則是基于Spring5中提供的WebFlux,屬于響應(yīng)式編程的實(shí)現(xiàn),具備更好的性能,所以我們接下來使用Gateway來對網(wǎng)關(guān)進(jìn)行實(shí)現(xiàn)。
2. 網(wǎng)關(guān)搭建
接下來我們就試著為userservice
和 orderservice
搭建網(wǎng)關(guān)。
2.1 引入依賴
首先初始化一個新的Module,將其初始化為空的Maven,統(tǒng)一網(wǎng)關(guān)實(shí)際上也是一個微服務(wù),所以也需要在Nacos上進(jìn)行注冊發(fā)現(xiàn),故添加如下依賴:
<dependencies>
<!-- nacos服務(wù)發(fā)現(xiàn)注冊依賴 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 網(wǎng)關(guān)gateway依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
2.2 創(chuàng)建啟動類
創(chuàng)建一個 GatewayApplication
的文件,將其當(dāng)做啟動類,該文件的內(nèi)容如下:
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
2.3 編寫配置
在網(wǎng)關(guān)這里,需要在 application.yml
配置中編寫路由配置以及nacos的地址等配置信息,配置文件中的配置信息如下所示:
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: user-service # 路由標(biāo)示,必須唯一
uri: lb://userservice # 路由的目標(biāo)地址,lb是負(fù)載均衡,后面跟服務(wù)名稱
predicates: # 路由斷言,判斷請求是否符合規(guī)則
- Path=/user/** # 路徑斷言,判斷路徑是否是以/user開頭,如果是則符合
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
從配置信息可以看到,網(wǎng)關(guān)實(shí)現(xiàn)了負(fù)載均衡以及路徑的斷言,讓訪問變得更加的輕松方便。
2.4 測試
接下來我們將 userservice, orderservice, gateway
三個服務(wù)都啟動,然后輸入網(wǎng)址 http://localhost:10010/user/1
可以看到用戶信息能夠順利顯示出來。
再輸入網(wǎng)址 http://localhost:10010/order/101
,能夠正確的顯示相關(guān)的信息,
這說明我們的網(wǎng)關(guān)構(gòu)建時成功的。
3. 路由斷言工廠
我們在配置文件中寫的斷言規(guī)則只是字符串,這些字符串會被Predicate Factory讀取并處理
轉(zhuǎn)變?yōu)槁酚膳袛嗟臈l件。
例如 Path=/user/**
是按照路徑匹配,這個規(guī)則是由 org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
類來處理的,像這樣的斷言工廠在SpringCloudGateway中還有十幾個。
Spring提供了11中基本的路由斷言工廠,11中工廠如下,
名稱 | 說明 |
---|---|
After | 只處理某個時間點(diǎn)后的請求 |
Before | 只處理某個時間點(diǎn)之前的請求 |
Between | 只處理某兩個時間點(diǎn)之前的請求 |
Cookie | 請求必須包含某些cookie才處理 |
Header | 請求必須包含某些header才處理 |
Host | 請求必須是訪問某個host(域名)才處理 |
Method | 請求方式必須是指定方式才處理 |
Path | 請求路徑必須符合指定規(guī)則才處理 |
Query | 請求參數(shù)必須包含指定參數(shù)才處理 |
RemoteAddr | 請求者的ip必須是指定范圍才處理 |
Weight | 權(quán)重處理 |
所有這些斷言工廠的實(shí)例都可以在Spring官網(wǎng)中找到。
比如我們需要只處理上海市2024年3月28日的orderservice請求,那么修改配置文件如下:
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: user-service # 路由標(biāo)示,必須唯一
uri: lb://userservice # 路由的目標(biāo)地址,lb是負(fù)載均衡,后面跟服務(wù)名稱
predicates: # 路由斷言,判斷請求是否符合規(guī)則
- Path=/user/** # 路徑斷言,判斷路徑是否是以/user開頭,如果是則符合
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
- After=2024-03-28T17:42:47.789-07:00[Asia/Shanghai]
上面僅新增了最后一行,這樣,因?yàn)楝F(xiàn)在是2023年,所以訪問 http://localhost:10010/order/101
必定會失效。
4. 路由過濾器
Gateway不可能所有請求都進(jìn)行響應(yīng),其會根據(jù)一些條件,將不符合的路徑進(jìn)行過濾,這也就是路由過濾器GatewayFilter的作用,對進(jìn)行網(wǎng)關(guān)的請求和微服務(wù)返回的響應(yīng)做出處理。
4.1 過濾器配置
Spring中提供了30+種不同的路由過濾器工廠,這里就不一一列舉出來了,所有的路由過濾器工廠都能在Spring官網(wǎng)進(jìn)行查看。
比如這里,可以使用過濾器給userservice 添加一個請求頭,添加如下:
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: user-service # 路由標(biāo)示,必須唯一
uri: lb://userservice # 路由的目標(biāo)地址,lb是負(fù)載均衡,后面跟服務(wù)名稱
predicates: # 路由斷言,判斷請求是否符合規(guī)則
- Path=/user/** # 路徑斷言,判斷路徑是否是以/user開頭,如果是則符合
filters:
- AddRequestHeader=Truth,I am a really ikun!
則上面的代碼會對所有的 userservice
服務(wù)添加一個請求頭。
如果想要對所有的請求都添加一個請求頭應(yīng)該怎么做呢?
只需要定義 default-filters
即可,定義的過濾器如下:
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: user-service # 路由標(biāo)示,必須唯一
uri: lb://userservice # 路由的目標(biāo)地址,lb是負(fù)載均衡,后面跟服務(wù)名稱
predicates: # 路由斷言,判斷請求是否符合規(guī)則
- Path=/user/** # 路徑斷言,判斷路徑是否是以/user開頭,如果是則符合
default-filters:
- AddRequestHeader=Truth,I am a really ikun!
4.2 全局過濾器
全局過濾器的作用也是處理一切進(jìn)入網(wǎng)關(guān)的請求和微服務(wù)響應(yīng),與 default-filters
的作用一樣區(qū)別在于 default-filters
通過配置定義,處理邏輯是固定的。而 GlobalFilter
的邏輯需要自己
寫代碼實(shí)現(xiàn)。
全局過濾器的實(shí)現(xiàn)步驟如下:
- 實(shí)現(xiàn)
GlobalFilter
接口 - 添加
@Order
注解或?qū)崿F(xiàn)Ordered
接口,目的是設(shè)置過濾的優(yōu)先級 - 編寫處理邏輯
比如我們定義一個全局過濾器,攔截請求,判斷請求的參數(shù)是或符合下面的條件:
- 參數(shù)中是否有
authorization
-
authorization
參數(shù)值是否為admin
如果同時滿足,則對請求進(jìn)行放行。
我們在 gateway
的Module中創(chuàng)新一個 AuthorizeFilter
的全局過濾文件,其文件內(nèi)容如下;
// @Order 注解定義過濾器優(yōu)先級,值越小,優(yōu)先級越高,也可以通過Ordered接口實(shí)現(xiàn)
@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.獲取請求參數(shù)
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2.獲取參數(shù)中的 authorization 參數(shù)
String auth = params.getFirst("authorization");
// 3.判斷參數(shù)值是否等于 admin
if ("admin".equals(auth)) {
// 4.是,放行
return chain.filter(exchange);
}
// 5.否,攔截
// 5.1.設(shè)置狀態(tài)碼
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2.攔截請求
return exchange.getResponse().setComplete();
}
}
之后再使用 http://localhost:10010/order/101
,則網(wǎng)頁會報告我們所設(shè)置的狀態(tài)碼的錯誤,錯誤如下:
而如果使用 http://localhost:10010/order/101?authorization=admin
, 則網(wǎng)頁能夠正常訪問。
4.3 過濾器執(zhí)行順序
請求進(jìn)入網(wǎng)關(guān)會碰到三類過濾器:當(dāng)前路由的過濾器、DefaultFilter、GlobalFilter
請求路由后,會將當(dāng)前路由過濾器和DefaultFilter、GlobalFilter,合并到一個過濾器鏈(集合)中,排序后依次執(zhí)行每個過濾器,那么過濾器鏈的執(zhí)行順序是怎樣的呢?
過濾器執(zhí)行順序如下:
- 每一個過濾器都必須指定一個int類型的order值,order值越小,優(yōu)先級越高,執(zhí)行順序越靠前。
-
GlobalFilter
通過實(shí)現(xiàn)Ordered
接口,或者添加@Order
注解來指定order
值,由我們自己指定 - 路由過濾器和
defaultFilter
的order
由Spring指定,默認(rèn)是按照聲明順序從1遞增。即如果定義了多個過濾器配置,則其第一行優(yōu)先級是1,第二行優(yōu)先級是2,以此類推 - 當(dāng)過濾器的
order
值一樣時,會按照defaultFilter
>路由過濾器
>GlobalFilter
的順序執(zhí)行。
5. 跨域問題處理
跨域問題指的是不同站點(diǎn)之間,使用 ajax 無法相互調(diào)用的問題。跨域問題本質(zhì)是瀏覽器的一種保護(hù)機(jī)制,它的初衷是為了保證用戶的安全,防止惡意網(wǎng)站竊取數(shù)據(jù),但這個保護(hù)機(jī)制也帶來了新的問題,它的問題是給不同站點(diǎn)之間的正常調(diào)用,也帶來的阻礙。簡單來說就是瀏覽器禁止請求的發(fā)起者與服務(wù)端發(fā)生跨域ajax請求,請求被瀏覽器攔截的問題。
在請求時,如果出現(xiàn)了以下情況中的任意一種,那么它就是跨域請求:
- 協(xié)議不同,如
http
和https
; - 域名不同;
- 端口不同。
也就是說,即使域名相同,如果一個使用的是 http
,另一個使用的是 https
,那么它們也屬于跨域訪問。常見的跨域問題如下圖所示:
當(dāng)前頁面 | 被請求頁面 | 是否跨域 |
---|---|---|
http://www.test.com/ | http://www.test.com/index.html | 否 |
http://www.test.com/ | https://www.test.com/index.html | 是,協(xié)議名不同(http,https) |
http://www.test.com/ | http://www.baidu.com/ | 是,主域名不同(test,baidu) |
http://www.test.com/ | http://blog.test.com/ | 是,子域名不同(www,blog) |
http://www.test.com:8080/ | http://www.test.com:8081/ | 是,端口不同(8080,8081) |
而解決跨域問題的方案就是 CORS
,CORS
是一個W3C標(biāo)準(zhǔn),全稱是”跨域資源共享”(Cross-origin resource sharing),允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。它通過服務(wù)器增加一個特殊的Header[Access-Control-Allow-Origin]來告訴客戶端跨域的限制,如果瀏覽器支持CORS、并且判斷Origin通過的話,就會允許XMLHttpRequest發(fā)起跨域請求。
網(wǎng)關(guān)處理跨域問題采用的方案同樣是CORS方案,且只需要經(jīng)行簡單的配置即可,配置如下:文章來源:http://www.zghlxwxcb.cn/news/detail-461051.html
spring:
cloud:
gateway:
globalcors: # 全局的跨域處理
add-to-simple-url-handler-mapping: true # 解決options請求被攔截問題
cors-configurations:
'[/**]': # 對哪些網(wǎng)址進(jìn)行配置,[/**] 指的是所有網(wǎng)址
allowedOrigins: # 允許哪些網(wǎng)站的跨域請求
- "http://localhost:8090"
- "http://www.leyou.com"
allowedMethods: # 允許的跨域AJAX請求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允許在請求頭中攜帶的頭信息
allowedCredentials: true # 是否允許攜帶cookie
maxAge: 360000 # 這次跨域檢測的有效期,有效期內(nèi)無需再次檢查請求
按照這種格式進(jìn)行配置即可解決跨域問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-461051.html
到了這里,關(guān)于SpringCloud學(xué)習(xí)(七)——統(tǒng)一網(wǎng)關(guān)Gateway的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!