springboot使用Gateway做網關并且配置全局攔截器的方式
一、為什么要用網關
統(tǒng)一入口:
- 作用:作為所有客戶端請求的統(tǒng)一入口。
- 說明:所有客戶端請求都通過網關進行路由,網關負責將請求轉發(fā)到后端的微服務
路由轉發(fā):
- 作用:根據(jù)請求的URL、方法等信息將請求路由到不同的微服務。
- 說明:網關可以根據(jù)配置的路由規(guī)則,將請求轉發(fā)到正確的微服務,實現(xiàn)請求的路由和負載均衡。
負載均衡:
- 作用:實現(xiàn)請求的負載均衡。
- 說明:網關可以集成負載均衡組件(如Ribbon),根據(jù)負載均衡策略將請求分發(fā)到不同的服務實例,提高系統(tǒng)的可用性和擴展性。
服務發(fā)現(xiàn):
- 作用:與服務注冊中心集成,實現(xiàn)服務的自動發(fā)現(xiàn)。
- 說明:網關可以與Eureka等服務注冊中心集成,動態(tài)獲取服務實例的信息,實現(xiàn)服務的自動發(fā)現(xiàn)和路由。
認證與授權:
- 作用:提供統(tǒng)一的安全認證和授權機制。
- 說明:網關可以集成認證和授權組件(如OAuth2、JWT),對所有進入的請求進行安全檢查,確保只有合法的請求才能訪問后端服務。
跨域資源共享(CORS):
- 作用:處理跨域請求。
- 說明:網關可以處理跨域請求,允許來自不同域的客戶端訪問后端服務,解決了瀏覽器的同源策略限制。
二、Gateway簡單使用
第一步:引入Gateway的maven依賴到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>
第二步:編寫配置文件application.yml文件,如下所示:
server: port: 10086 # 網關端口 spring: application: name: gateway # 服務名稱 cloud: nacos: server-addr: localhost:8848 # nacos 地址 gateway: routes: # 網關路由配置 - id: provider # 路由id,自定義,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目標地址 (直接寫死地址的方式,不推薦) uri: lb://provider # 路由的目標地址 lb是負載均衡,后面跟服務名稱(推薦) predicates: # 路由斷言,判斷請求是否符合路由規(guī)則的條件 - Path=/provider/** # 按照路徑匹配,以/user/開頭的請求就符合要求
第三步:啟動測試
當然要注意的是我們需要開啟另一個服務provider服務,并且這個服務需要配置方法前綴/provider,當我們通過網關訪問的時候就可以直接的訪問到provider服務了。
三、Gateway斷言工廠
路由斷言主要用來判斷路由的規(guī)則。
配置文件中寫的斷言規(guī)則只是字符串,這些字符串會被Predicate Factory
讀取并處理。
例如Path=/user/**
是按照路徑匹配,這個規(guī)則是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
類來處理。
像這樣的斷言工廠在SpringCloudGateway還有十幾個:
當然這個地方可能給的不是很全所以我貼出官網地址:大家需要的可以去看官網:Spring Cloud Gateway
簡單示例,下面我配置一個在訪問之前需要到一定的時間才可以訪問,并且看一下效果
server: port: 10086 # 網關端口 spring: application: name: gateway # 服務名稱 cloud: nacos: server-addr: localhost:8848 # nacos 地址 gateway: routes: # 網關路由配置 - id: provider # 路由id,自定義,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目標地址 (直接寫死地址的方式,不推薦) uri: lb://provider # 路由的目標地址 lb是負載均衡,后面跟服務名稱(推薦) predicates: # 路由斷言,判斷請求是否符合路由規(guī)則的條件 - Path=/provider/** # 按照路徑匹配,以/user/開頭的請求就符合要求 - After=2031-01-20T17:42:47.789-07:00[America/Denver]
因為我配置了需要在2031年1月20號后才可以訪問明顯現(xiàn)在是2024年不可以訪問到,所以會報錯404。
四、Gateway路由過濾器
客戶端請求先找到路由,路由匹配時經過過濾器層層篩選,最終訪問到微服務。
當然微服務的請求反悔時,也會經過過濾器的篩選,只不過我們一般只對請求過濾,而不會對響應過濾。
SpringCloudGateWay目前已經提供了34種不同的過濾器工廠。感興趣的大家也可以去上面給出的官網地址查看。
下面我在路由過濾器中添加一個請求頭,并且需要在provider請求中加入一個參數(shù)去拿到請求頭中的參數(shù)
server: port: 10086 # 網關端口 spring: application: name: gateway # 服務名稱 cloud: nacos: server-addr: localhost:8848 # nacos 地址 gateway: routes: # 網關路由配置 - id: provider # 路由id,自定義,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目標地址 (直接寫死地址的方式,不推薦) uri: lb://provider # 路由的目標地址 lb是負載均衡,后面跟服務名稱(推薦) predicates: # 路由斷言,判斷請求是否符合路由規(guī)則的條件 - Path=/provider/** # 按照路徑匹配,以/user/開頭的請求就符合要求 filters: # 過濾器配置 - AddRequestHeader=token, test # 添加請求頭
provider請求變?yōu)?,需要拿到請求頭中的信息
@GetMapping("/provider/t") public String t(@RequestHeader(value = "token",required = false)String token){ return "恭喜您測試成功啦!"+token; }
測試
當然這是局部配置我們也可以針對所有的路由進行全局配置(但是這個配置是需要和路由s是同級的),如下所示:
server: port: 10086 # 網關端口 spring: application: name: gateway # 服務名稱 cloud: nacos: server-addr: localhost:8848 # nacos 地址 gateway: routes: # 網關路由配置 - id: provider # 路由id,自定義,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目標地址 (直接寫死地址的方式,不推薦) uri: lb://provider # 路由的目標地址 lb是負載均衡,后面跟服務名稱(推薦) predicates: # 路由斷言,判斷請求是否符合路由規(guī)則的條件 - Path=/provider/** # 按照路徑匹配,以/user/開頭的請求就符合要求 default-filters: # 默認過濾器配置 - AddRequestHeader=token, test # 添加請求頭
五、Gateway全局過濾器
上面的gateway路由器可以配置全局的,為什么還需要有一個全局過濾器呢,因為上面的過濾器都是只可以針對與一些邏輯的攔截,但是不可以涉及到一些業(yè)務的處理,所以就有這個全局過濾器可以通過編寫代碼的方式來編寫業(yè)務邏輯進行對用戶訪問的鑒權放行等等。
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.獲取請求參數(shù) //1.這里的request并不是servlet中的request //2.返回值是一個多鍵的map集合、也就是說這個map集合的鍵可以重復 MultiValueMap<String, String> params = exchange.getRequest().getQueryParams(); // 2.獲取userName參數(shù) String userName = params.getFirst("userName"); // 3.校驗 if ("root".equals(userName)) { // 放行 return chain.filter(exchange); } // 4.攔截 // 4.1.禁止訪問,設置狀態(tài)碼 exchange.getResponse().setStatusCode(HttpStatus.valueOf(500)); // 4.2.結束處理 return exchange.getResponse().setComplete(); } //過濾器優(yōu)先級,數(shù)字越小優(yōu)先級越高 @Override public int getOrder() { return -1; } }
測試:
我們先正常的訪問之前的請求,會發(fā)現(xiàn)無法使用此頁面也就是被拒絕訪問了
當我們加上一個參數(shù)后把userName=root加上之后就可以正確的訪問到請求了
過濾器鏈執(zhí)行順序
SpringCloudGateWay中,有三種過濾器:
- 默認過濾器default-filters
- 只對具體某個路由生效的局部過濾器filters
- 使用java代碼編寫的全局過濾器GlobalFilter
過濾器最終都會轉化成GlobalFilter(使用的是適配器模式)所以我們就可以把這三種過濾器看成一個整體而順序也入下圖顯示的一致。
由上圖知過濾器的執(zhí)行順序為:默認過濾器 → 當前路由過濾器 → 全局過濾器。
六、Gateway跨域請求配置
1.跨域請求定義
跨域:請求位置和被請求位置不同源就會發(fā)生跨域。
這里的不同源包括兩個點:
- 域名不同:www.baidu.com 和 www.taobao.com。(IP不同也是相同道理)
- 端口不同:127.0.0.1:8080和127.0.0.1:8081。
而瀏覽器又會禁止請求的發(fā)起者與服務端發(fā)生跨域AJAX請求。
如果發(fā)生了跨域請求,服務器端是能夠正常響應的,但是響應的結果會被瀏覽器攔截。
2.跨域常見解決方案
使用CORS方式。
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務器,發(fā)出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
3.跨域請求解決方案
方式一:配置application.yml文件:
spring: cloud: gateway: globalcors: # 全局的跨域配置 add-to-simple-url-handler-mapping: true # 解決options請求被攔截問題 # options請求 就是一種詢問服務器是否瀏覽器可以跨域的請求 # 如果每次跨域都有詢問服務器是否瀏覽器可以跨域對性能也是損耗 # 可以配置本次跨域檢測的有效期maxAge # 在maxAge設置的時間范圍內,不去詢問,統(tǒng)統(tǒng)允許跨域 corsConfigurations: '[/**]': allowedOrigins: # 允許哪些網站的跨域請求 - "http://localhost:8090" allowedMethods: # 允許的跨域ajax的請求方式 - "GET" - "POST" - "DELETE" - "PUT" - "OPTIONS" allowedHeaders: "*" # 允許在請求中攜帶的頭信息 allowCredentials: true # 允許在請求中攜帶cookie maxAge: 360000 # 本次跨域檢測的有效期(單位毫秒) # 有效期內,跨域請求不會一直發(fā)option請求去增大服務器壓力
方式二:使用編碼方式定義配置類:
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自帶的跨域檢測工具類判斷當前請求是否跨域 if (!CorsUtils.isCorsRequest(request)) { return chain.filter(ctx); } HttpHeaders requestHeaders = request.getHeaders(); // 獲取請求頭 ServerHttpResponse response = ctx.getResponse(); // 獲取響應對象 HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); // 獲取請求方式對象 HttpHeaders headers = response.getHeaders(); // 獲取響應頭 headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); // 把請求頭中的請求源(協(xié)議+ip+端口)添加到響應頭中(相當于yml中的allowedOrigins) headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders()); if (requestMethod != null) { headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name()); // 允許被響應的方法(GET/POST等,相當于yml中的allowedMethods) } headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); // 允許在請求中攜帶cookie(相當于yml中的allowCredentials) headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); // 允許在請求中攜帶的頭信息(相當于yml中的allowedHeaders) headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE); // 本次跨域檢測的有效期(單位毫秒,相當于yml中的maxAge) if (request.getMethod() == HttpMethod.OPTIONS) { // 直接給option請求反回結果 response.setStatusCode(HttpStatus.OK); return Mono.empty(); } return chain.filter(ctx); // 不是option請求則放行 }; } }
到此這篇關于springboot使用Gateway做網關并且配置全局攔截器的文章就介紹到這了,更多相關springboot Gateway全局攔截器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
淺談java Iterator.remove()方法的用法(詳解)
下面小編就為大家?guī)硪黄獪\談java Iterator.remove()方法的用法(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01Spring?Boot+Aop記錄用戶操作日志實戰(zhàn)記錄
在Spring框架中使用AOP配合自定義注解可以方便的實現(xiàn)用戶操作的監(jiān)控,下面這篇文章主要給大家介紹了關于Spring?Boot+Aop記錄用戶操作日志實戰(zhàn)的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-04-04SpringBoot整合Mybatis Plus多數(shù)據(jù)源的實現(xiàn)示例
本文主要介紹了SpringBoot整合Mybatis Plus多數(shù)據(jù)源的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11springboot3生成本地文件url的實現(xiàn)示例
本文主要介紹了springboot3生成本地文件url的實現(xiàn)示例,從而提供一種高效的文件管理方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-01-01關于Spring?Validation數(shù)據(jù)校檢的使用流程分析
在實際項目中,對客戶端傳遞到服務端的參數(shù)進行校驗至關重要,SpringValidation提供了一種便捷的方式來實現(xiàn)這一需求,通過在POJO類的屬性上添加檢查注解,本文給大家介紹Spring?Validation數(shù)據(jù)校檢的使用流程,感興趣的朋友一起看看吧2024-11-11