springboot使用Gateway做網(wǎng)關(guān)并且配置全局?jǐn)r截器的方式
一、為什么要用網(wǎng)關(guān)
統(tǒng)一入口:
- 作用:作為所有客戶(hù)端請(qǐng)求的統(tǒng)一入口。
- 說(shuō)明:所有客戶(hù)端請(qǐng)求都通過(guò)網(wǎng)關(guān)進(jìn)行路由,網(wǎng)關(guān)負(fù)責(zé)將請(qǐng)求轉(zhuǎn)發(fā)到后端的微服務(wù)
路由轉(zhuǎn)發(fā):
- 作用:根據(jù)請(qǐng)求的URL、方法等信息將請(qǐng)求路由到不同的微服務(wù)。
- 說(shuō)明:網(wǎng)關(guān)可以根據(jù)配置的路由規(guī)則,將請(qǐng)求轉(zhuǎn)發(fā)到正確的微服務(wù),實(shí)現(xiàn)請(qǐng)求的路由和負(fù)載均衡。
負(fù)載均衡:
- 作用:實(shí)現(xiàn)請(qǐng)求的負(fù)載均衡。
- 說(shuō)明:網(wǎng)關(guān)可以集成負(fù)載均衡組件(如Ribbon),根據(jù)負(fù)載均衡策略將請(qǐng)求分發(fā)到不同的服務(wù)實(shí)例,提高系統(tǒng)的可用性和擴(kuò)展性。
服務(wù)發(fā)現(xiàn):
- 作用:與服務(wù)注冊(cè)中心集成,實(shí)現(xiàn)服務(wù)的自動(dòng)發(fā)現(xiàn)。
- 說(shuō)明:網(wǎng)關(guān)可以與Eureka等服務(wù)注冊(cè)中心集成,動(dòng)態(tài)獲取服務(wù)實(shí)例的信息,實(shí)現(xiàn)服務(wù)的自動(dòng)發(fā)現(xiàn)和路由。
認(rèn)證與授權(quán):
- 作用:提供統(tǒng)一的安全認(rèn)證和授權(quán)機(jī)制。
- 說(shuō)明:網(wǎng)關(guān)可以集成認(rèn)證和授權(quán)組件(如OAuth2、JWT),對(duì)所有進(jìn)入的請(qǐng)求進(jìn)行安全檢查,確保只有合法的請(qǐng)求才能訪(fǎng)問(wèn)后端服務(wù)。
跨域資源共享(CORS):
- 作用:處理跨域請(qǐng)求。
- 說(shuō)明:網(wǎng)關(guān)可以處理跨域請(qǐng)求,允許來(lái)自不同域的客戶(hù)端訪(fǎng)問(wèn)后端服務(wù),解決了瀏覽器的同源策略限制。

二、Gateway簡(jiǎn)單使用
第一步:引入Gateway的maven依賴(lài)到pom.xml文件
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>第二步:編寫(xiě)配置文件application.yml文件,如下所示:
server:
port: 10086 # 網(wǎng)關(guān)端口
spring:
application:
name: gateway # 服務(wù)名稱(chēng)
cloud:
nacos:
server-addr: localhost:8848 # nacos 地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: provider # 路由id,自定義,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目標(biāo)地址 (直接寫(xiě)死地址的方式,不推薦)
uri: lb://provider # 路由的目標(biāo)地址 lb是負(fù)載均衡,后面跟服務(wù)名稱(chēng)(推薦)
predicates: # 路由斷言,判斷請(qǐng)求是否符合路由規(guī)則的條件
- Path=/provider/** # 按照路徑匹配,以/user/開(kāi)頭的請(qǐng)求就符合要求第三步:?jiǎn)?dòng)測(cè)試

當(dāng)然要注意的是我們需要開(kāi)啟另一個(gè)服務(wù)provider服務(wù),并且這個(gè)服務(wù)需要配置方法前綴/provider,當(dāng)我們通過(guò)網(wǎng)關(guān)訪(fǎng)問(wèn)的時(shí)候就可以直接的訪(fǎng)問(wèn)到provider服務(wù)了。
三、Gateway斷言工廠(chǎng)
路由斷言主要用來(lái)判斷路由的規(guī)則。
配置文件中寫(xiě)的斷言規(guī)則只是字符串,這些字符串會(huì)被Predicate Factory讀取并處理。
例如Path=/user/**是按照路徑匹配,這個(gè)規(guī)則是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory類(lèi)來(lái)處理。
像這樣的斷言工廠(chǎng)在SpringCloudGateway還有十幾個(gè):

當(dāng)然這個(gè)地方可能給的不是很全所以我貼出官網(wǎng)地址:大家需要的可以去看官網(wǎng):Spring Cloud Gateway
簡(jiǎn)單示例,下面我配置一個(gè)在訪(fǎng)問(wèn)之前需要到一定的時(shí)間才可以訪(fǎng)問(wèn),并且看一下效果
server:
port: 10086 # 網(wǎng)關(guān)端口
spring:
application:
name: gateway # 服務(wù)名稱(chēng)
cloud:
nacos:
server-addr: localhost:8848 # nacos 地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: provider # 路由id,自定義,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目標(biāo)地址 (直接寫(xiě)死地址的方式,不推薦)
uri: lb://provider # 路由的目標(biāo)地址 lb是負(fù)載均衡,后面跟服務(wù)名稱(chēng)(推薦)
predicates: # 路由斷言,判斷請(qǐng)求是否符合路由規(guī)則的條件
- Path=/provider/** # 按照路徑匹配,以/user/開(kāi)頭的請(qǐng)求就符合要求
- After=2031-01-20T17:42:47.789-07:00[America/Denver]因?yàn)槲遗渲昧诵枰?031年1月20號(hào)后才可以訪(fǎng)問(wèn)明顯現(xiàn)在是2024年不可以訪(fǎng)問(wèn)到,所以會(huì)報(bào)錯(cuò)404。

四、Gateway路由過(guò)濾器
客戶(hù)端請(qǐng)求先找到路由,路由匹配時(shí)經(jīng)過(guò)過(guò)濾器層層篩選,最終訪(fǎng)問(wèn)到微服務(wù)。
當(dāng)然微服務(wù)的請(qǐng)求反悔時(shí),也會(huì)經(jīng)過(guò)過(guò)濾器的篩選,只不過(guò)我們一般只對(duì)請(qǐng)求過(guò)濾,而不會(huì)對(duì)響應(yīng)過(guò)濾。
SpringCloudGateWay目前已經(jīng)提供了34種不同的過(guò)濾器工廠(chǎng)。感興趣的大家也可以去上面給出的官網(wǎng)地址查看。
下面我在路由過(guò)濾器中添加一個(gè)請(qǐng)求頭,并且需要在provider請(qǐng)求中加入一個(gè)參數(shù)去拿到請(qǐng)求頭中的參數(shù)
server:
port: 10086 # 網(wǎng)關(guān)端口
spring:
application:
name: gateway # 服務(wù)名稱(chēng)
cloud:
nacos:
server-addr: localhost:8848 # nacos 地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: provider # 路由id,自定義,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目標(biāo)地址 (直接寫(xiě)死地址的方式,不推薦)
uri: lb://provider # 路由的目標(biāo)地址 lb是負(fù)載均衡,后面跟服務(wù)名稱(chēng)(推薦)
predicates: # 路由斷言,判斷請(qǐng)求是否符合路由規(guī)則的條件
- Path=/provider/** # 按照路徑匹配,以/user/開(kāi)頭的請(qǐng)求就符合要求
filters: # 過(guò)濾器配置
- AddRequestHeader=token, test # 添加請(qǐng)求頭provider請(qǐng)求變?yōu)椋枰玫秸?qǐng)求頭中的信息
@GetMapping("/provider/t")
public String t(@RequestHeader(value = "token",required = false)String token){
return "恭喜您測(cè)試成功啦!"+token;
}測(cè)試

當(dāng)然這是局部配置我們也可以針對(duì)所有的路由進(jìn)行全局配置(但是這個(gè)配置是需要和路由s是同級(jí)的),如下所示:
server:
port: 10086 # 網(wǎng)關(guān)端口
spring:
application:
name: gateway # 服務(wù)名稱(chēng)
cloud:
nacos:
server-addr: localhost:8848 # nacos 地址
gateway:
routes: # 網(wǎng)關(guān)路由配置
- id: provider # 路由id,自定義,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目標(biāo)地址 (直接寫(xiě)死地址的方式,不推薦)
uri: lb://provider # 路由的目標(biāo)地址 lb是負(fù)載均衡,后面跟服務(wù)名稱(chēng)(推薦)
predicates: # 路由斷言,判斷請(qǐng)求是否符合路由規(guī)則的條件
- Path=/provider/** # 按照路徑匹配,以/user/開(kāi)頭的請(qǐng)求就符合要求
default-filters: # 默認(rèn)過(guò)濾器配置
- AddRequestHeader=token, test # 添加請(qǐng)求頭五、Gateway全局過(guò)濾器
上面的gateway路由器可以配置全局的,為什么還需要有一個(gè)全局過(guò)濾器呢,因?yàn)樯厦娴倪^(guò)濾器都是只可以針對(duì)與一些邏輯的攔截,但是不可以涉及到一些業(yè)務(wù)的處理,所以就有這個(gè)全局過(guò)濾器可以通過(guò)編寫(xiě)代碼的方式來(lái)編寫(xiě)業(yè)務(wù)邏輯進(jìn)行對(duì)用戶(hù)訪(fǎng)問(wèn)的鑒權(quán)放行等等。
package com.example.demo.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class GateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.獲取請(qǐng)求參數(shù)
//1.這里的request并不是servlet中的request
//2.返回值是一個(gè)多鍵的map集合、也就是說(shuō)這個(gè)map集合的鍵可以重復(fù)
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
// 2.獲取userName參數(shù)
String userName = params.getFirst("userName");
// 3.校驗(yàn)
if ("root".equals(userName)) {
// 放行
return chain.filter(exchange);
}
// 4.攔截
// 4.1.禁止訪(fǎng)問(wèn),設(shè)置狀態(tài)碼
exchange.getResponse().setStatusCode(HttpStatus.valueOf(500));
// 4.2.結(jié)束處理
return exchange.getResponse().setComplete();
}
//過(guò)濾器優(yōu)先級(jí),數(shù)字越小優(yōu)先級(jí)越高
@Override
public int getOrder() {
return -1;
}
}測(cè)試:
我們先正常的訪(fǎng)問(wèn)之前的請(qǐng)求,會(huì)發(fā)現(xiàn)無(wú)法使用此頁(yè)面也就是被拒絕訪(fǎng)問(wèn)了

當(dāng)我們加上一個(gè)參數(shù)后把userName=root加上之后就可以正確的訪(fǎng)問(wèn)到請(qǐng)求了

過(guò)濾器鏈執(zhí)行順序
SpringCloudGateWay中,有三種過(guò)濾器:
- 默認(rèn)過(guò)濾器default-filters
- 只對(duì)具體某個(gè)路由生效的局部過(guò)濾器filters
- 使用java代碼編寫(xiě)的全局過(guò)濾器GlobalFilter
過(guò)濾器最終都會(huì)轉(zhuǎn)化成GlobalFilter(使用的是適配器模式)所以我們就可以把這三種過(guò)濾器看成一個(gè)整體而順序也入下圖顯示的一致。

由上圖知過(guò)濾器的執(zhí)行順序?yàn)椋耗J(rèn)過(guò)濾器 → 當(dāng)前路由過(guò)濾器 → 全局過(guò)濾器。
六、Gateway跨域請(qǐng)求配置
1.跨域請(qǐng)求定義
跨域:請(qǐng)求位置和被請(qǐng)求位置不同源就會(huì)發(fā)生跨域。
這里的不同源包括兩個(gè)點(diǎn):
- 域名不同:www.baidu.com 和 www.taobao.com。(IP不同也是相同道理)
- 端口不同:127.0.0.1:8080和127.0.0.1:8081。
而瀏覽器又會(huì)禁止請(qǐng)求的發(fā)起者與服務(wù)端發(fā)生跨域AJAX請(qǐng)求。
如果發(fā)生了跨域請(qǐng)求,服務(wù)器端是能夠正常響應(yīng)的,但是響應(yīng)的結(jié)果會(huì)被瀏覽器攔截。
2.跨域常見(jiàn)解決方案
使用CORS方式。
CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱(chēng)是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制。
3.跨域請(qǐng)求解決方案
方式一:配置application.yml文件:
spring:
cloud:
gateway:
globalcors: # 全局的跨域配置
add-to-simple-url-handler-mapping: true # 解決options請(qǐng)求被攔截問(wèn)題
# options請(qǐng)求 就是一種詢(xún)問(wèn)服務(wù)器是否瀏覽器可以跨域的請(qǐng)求
# 如果每次跨域都有詢(xún)問(wèn)服務(wù)器是否瀏覽器可以跨域?qū)π阅芤彩菗p耗
# 可以配置本次跨域檢測(cè)的有效期maxAge
# 在maxAge設(shè)置的時(shí)間范圍內(nèi),不去詢(xún)問(wèn),統(tǒng)統(tǒng)允許跨域
corsConfigurations:
'[/**]':
allowedOrigins: # 允許哪些網(wǎng)站的跨域請(qǐng)求
- "http://localhost:8090"
allowedMethods: # 允許的跨域ajax的請(qǐng)求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允許在請(qǐng)求中攜帶的頭信息
allowCredentials: true # 允許在請(qǐng)求中攜帶cookie
maxAge: 360000 # 本次跨域檢測(cè)的有效期(單位毫秒)
# 有效期內(nèi),跨域請(qǐng)求不會(huì)一直發(fā)option請(qǐng)求去增大服務(wù)器壓力方式二:使用編碼方式定義配置類(lèi):
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Configuration
public class CorsConfig {
private static final String MAX_AGE = "18000L";
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
// 使用SpringMvc自帶的跨域檢測(cè)工具類(lèi)判斷當(dāng)前請(qǐng)求是否跨域
if (!CorsUtils.isCorsRequest(request)) {
return chain.filter(ctx);
}
HttpHeaders requestHeaders = request.getHeaders(); // 獲取請(qǐng)求頭
ServerHttpResponse response = ctx.getResponse(); // 獲取響應(yīng)對(duì)象
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); // 獲取請(qǐng)求方式對(duì)象
HttpHeaders headers = response.getHeaders(); // 獲取響應(yīng)頭
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); // 把請(qǐng)求頭中的請(qǐng)求源(協(xié)議+ip+端口)添加到響應(yīng)頭中(相當(dāng)于yml中的allowedOrigins)
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
if (requestMethod != null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name()); // 允許被響應(yīng)的方法(GET/POST等,相當(dāng)于yml中的allowedMethods)
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); // 允許在請(qǐng)求中攜帶cookie(相當(dāng)于yml中的allowCredentials)
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); // 允許在請(qǐng)求中攜帶的頭信息(相當(dāng)于yml中的allowedHeaders)
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE); // 本次跨域檢測(cè)的有效期(單位毫秒,相當(dāng)于yml中的maxAge)
if (request.getMethod() == HttpMethod.OPTIONS) { // 直接給option請(qǐng)求反回結(jié)果
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
return chain.filter(ctx); // 不是option請(qǐng)求則放行
};
}
}到此這篇關(guān)于springboot使用Gateway做網(wǎng)關(guān)并且配置全局?jǐn)r截器的文章就介紹到這了,更多相關(guān)springboot Gateway全局?jǐn)r截器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實(shí)現(xiàn)日志鏈路追蹤的項(xiàng)目實(shí)踐
在分布式系統(tǒng)中,由于請(qǐng)求的處理過(guò)程可能會(huì)跨越多個(gè)服務(wù),因此,對(duì)請(qǐng)求的追蹤變得尤為重要,本文主要介紹了SpringBoot實(shí)現(xiàn)日志鏈路追蹤的項(xiàng)目實(shí)踐,感興趣的可以了解一下2024-03-03
SpringBoot配置嵌入式Servlet容器和使用外置Servlet容器的教程圖解
這篇文章主要介紹了SpringBoot配置嵌入式Servlet容器和使用外置Servlet容器的教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
springboot+VUE前后端分離實(shí)現(xiàn)疫情防疫平臺(tái)JAVA
本文主要使用了Java、springmvc、VUE、node.js、mybatis、mysql、tomcat、jquery、layui、bootstarp、JavaScript、html、css、jsp、log4j等一些常見(jiàn)的基本技術(shù),實(shí)現(xiàn)一個(gè)疫情防疫小平臺(tái)2021-08-08
SpringBoot+Redis Bitmap實(shí)現(xiàn)活躍用戶(hù)統(tǒng)計(jì)
Redis的Bitmap數(shù)據(jù)結(jié)構(gòu)是一種緊湊的位圖,它可以用于實(shí)現(xiàn)各種場(chǎng)景,其中統(tǒng)計(jì)活躍用戶(hù)是一種經(jīng)典的業(yè)務(wù)場(chǎng)景,下面我們就來(lái)學(xué)習(xí)一下SpringBoot如何利用Redis中的Bitmap實(shí)現(xiàn)活躍用戶(hù)統(tǒng)計(jì)吧2023-11-11
Idea創(chuàng)建springboot不能選擇java8的解決
在IDEA 2023版本創(chuàng)建Spring Boot項(xiàng)目時(shí),發(fā)現(xiàn)沒(méi)有Java 8選項(xiàng),只有Java 17和Java 20,解決方法包括:通過(guò)修改服務(wù)器URL(推薦)或直接在創(chuàng)建后修改pom.xml文件中的Spring Boot和Java版本2025-01-01
詳解Spring緩存注解@Cacheable,@CachePut , @CacheEvict使用
這篇文章主要介紹了詳解Spring緩存注解@Cacheable,@CachePut , @CacheEvict使用,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05
解決使用this.getClass().getResource()獲取文件時(shí)遇到的坑
這篇文章主要介紹了解決使用this.getClass().getResource()獲取文件時(shí)遇到的坑問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
SpringCloud如何使用Eureka實(shí)現(xiàn)服務(wù)之間的傳遞數(shù)據(jù)
這篇文章主要介紹了SpringCloud使用Eureka實(shí)現(xiàn)服務(wù)之間的傳遞數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06

