目錄
Gateway網(wǎng)關(guān)
1.0.為什么需要網(wǎng)關(guān)?
1.1.如何使用gateway網(wǎng)關(guān)
1.2.網(wǎng)關(guān)從注冊中心拉取服務(wù)
1.3.gateway自動定位
1.4.gateway常見的斷言
1.5.gateway內(nèi)置的過濾器
1.6.自定義過濾器-全局過濾器
1.7.解決跨域問題
2.nginx反向代理gateway集群
2.1.配置文件
繼? nacos注冊中心+Ribbon負(fù)載均衡+完成openfeign的調(diào)用(超詳細(xì)步驟)?文章擴(kuò)展Gateway網(wǎng)關(guān)
常見的API網(wǎng)關(guān):
?Ngnix+lua
使用nginx的反向代理和負(fù)載均衡可實現(xiàn)對api服務(wù)器的負(fù)載均衡及高可用、lua是一種腳本語言,可以來編寫一些簡單的邏輯, nginx支持lua腳本
Kong
基于Nginx+Lua開發(fā),性能高,穩(wěn)定,有多個可用的插件(限流、鑒權(quán)等等)可以開箱即用。 問題:
只支持Http協(xié)議;二次開發(fā),自由擴(kuò)展困難;提供管理API,缺乏更易用的管控、配置方式。
Zuul 1.0----老的微服務(wù)項目
Netflix開源的網(wǎng)關(guān),功能豐富,使用JAVA開發(fā),易于二次開發(fā) 問題:缺乏管控,無法動態(tài)配
置;依賴組件較多;處理Http請求依賴的是Web容器,性能不如Nginx
Netflix提出理論---Zuul2.0 遠(yuǎn)遠(yuǎn)超過1.0---實際的產(chǎn)品沒有出來。
Spring Cloud Gateway
Spring公司為了替換Zuul而開發(fā)的網(wǎng)關(guān)服務(wù),將在下面具體介紹。
注意:SpringCloud alibaba技術(shù)棧中并沒有提供自己的網(wǎng)關(guān),我們可以采用Spring Cloud Gateway來做網(wǎng)關(guān)
Gateway網(wǎng)關(guān)
Gateway簡介
Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等術(shù)開發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡單有效的統(tǒng)一的 API 路由管理方式。它的目標(biāo)是替代 Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且基于 Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全,監(jiān)控和限流。
1.0.為什么需要網(wǎng)關(guān)?
Gateway網(wǎng)關(guān)是我們服務(wù)的守門神,所有微服務(wù)的統(tǒng)一入口。
網(wǎng)關(guān)的核心功能特性:
請求路由
權(quán)限控制
限流
架構(gòu)圖:
- 權(quán)限控制:
- 網(wǎng)關(guān)作為微服務(wù)入口,需要校驗用戶是是否有請求資格,如果沒有則進(jìn)行攔截。
- 路由和負(fù)載均衡:
- 一切請求都必須先經(jīng)過gateway,但網(wǎng)關(guān)不處理業(yè)務(wù),而是根據(jù)某種規(guī)則,把請求轉(zhuǎn)發(fā)到某個微服務(wù),這個過程叫做路由。當(dāng)然路由的目標(biāo)服務(wù)有多個時,還需要做負(fù)載均衡。
- 限流:
- 當(dāng)請求流量過高時,在網(wǎng)關(guān)中按照下流的微服務(wù)能夠接受的速度來放行請求,避免服務(wù)壓力過大。
1.1.如何使用gateway網(wǎng)關(guān)
(1).創(chuàng)建一個網(wǎng)關(guān)微服務(wù)模塊并引用依賴
<dependencies> <!--引入gateway依賴--> <!--不能再引入spring-boot-starter-web依賴,因為web依賴中存在tomcat服務(wù)器--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies>
(2).創(chuàng)建配置文件
#端口號 server: port: 81 #服務(wù)名稱 spring: application: name: qy165-gateway #配置路由轉(zhuǎn)發(fā)規(guī)則 cloud: gateway: routes: - id: qy165-product #路由的標(biāo)識 唯一即可 默認(rèn)按照UUID生成 uri: http://localhost:8001 #真實路由轉(zhuǎn)發(fā)的地址 predicates: #斷言:只要滿足斷言條件才會幫你轉(zhuǎn)發(fā)到相應(yīng)的url地址 - Path=/product/** - id: qy165-order uri: http://localhost:9001 predicates: - Path=/order/**
(3).啟動類
@SpringBootApplication public class GatewayApp { public static void main(String[] args) { SpringApplication.run(GatewayApp.class,args); } }
測試
發(fā)現(xiàn)uri地址是一個死數(shù)據(jù),未來可以是集群。
如何解決?
我們也可以把網(wǎng)關(guān)交于注冊中心來管理,那么網(wǎng)關(guān)就可以從注冊中心拉取服務(wù)信息。
1.2.網(wǎng)關(guān)從注冊中心拉取服務(wù)
(1).在網(wǎng)關(guān)微服務(wù)中引入nacos注冊中心依賴
<!--nacos注冊中心的依賴--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
(2).修改網(wǎng)關(guān)的配置
#端口號 server: port: 81 #服務(wù)名稱 spring: application: name: qy165-gateway #配置路由轉(zhuǎn)發(fā)規(guī)則 cloud: gateway: routes: - id: qy165-product #路由的標(biāo)識 唯一即可 默認(rèn)按照UUID生成 uri: lb://qy165-product #真實路由轉(zhuǎn)發(fā)的地址:lb://微服務(wù)的名稱 predicates: #斷言:只要滿足斷言條件才會幫你轉(zhuǎn)發(fā)到相應(yīng)的url地址 - Path=/product/** - id: qy165-order uri: lb://qy165-order predicates: - Path=/order/** #指定注冊中心的地址 nacos: discovery: server-addr: localhost:8848 register-enabled: false #只拉取不注冊
思考: 如果未來有1w個微服務(wù),那么就需要在gateway中配置1w微服務(wù)的路由
解決方案: 可以使用gateway自動定位功能
1.3.gateway自動定位
修改配置文件
#端口號 server: port: 81 #服務(wù)名稱 spring: application: name: qy165-gateway #指定注冊中心的地址 nacos: discovery: server-addr: localhost:8848 register-enabled: false #只拉取不注冊 #開啟微服務(wù)自動定位功能 cloud: gateway: discovery: locator: enabled: true
?測試
原理: ?
1.4.gateway常見的斷言
基于Datetime類型的斷言工廠
此類型的斷言根據(jù)時間做判斷,主要有三個:
AfterRoutePredicateFactory: 接收一個日期參數(shù),判斷請求日期是否晚于指定日期
BeforeRoutePredicateFactory: 接收一個日期參數(shù),判斷請求日期是否早于指定日期
BetweenRoutePredicateFactory: 接收兩個日期參數(shù),判斷請求日期是否在指定時間段內(nèi)
演示:
- After=2023-12-31T23:59:59.789+08:00[Asia/Shanghai]
基于遠(yuǎn)程地址的斷言工廠RemoteAddrRoutePredicateFactory
接收一個IP地址段,判斷請求主機(jī)地址是否在地址段中
演示:?
-RemoteAddr=172.16.7.128/24? ?(24--代表同一個域內(nèi)都可以訪問)
基于Cookie的斷言工廠
CookieRoutePredicateFactory:接收兩個參數(shù),cookie 名字和一個正則表達(dá)式。 判斷請求
cookie是否具有給定名稱且值與正則表達(dá)式匹配。
-Cookie=chocolate, ch.
基于Header的斷言工廠
HeaderRoutePredicateFactory:接收兩個參數(shù),標(biāo)題名稱和正則表達(dá)式。 判斷請求Header是否
具有給定名稱且值與正則表達(dá)式匹配。 key value
演示:?
-Header=X-Request-Id, \d+
基于Host的斷言工廠
HostRoutePredicateFactory:接收一個參數(shù),主機(jī)名模式。判斷請求的Host是否滿足匹配規(guī)則。
-Host=**.testhost.org
基于Method請求方法的斷言工廠
MethodRoutePredicateFactory:接收一個參數(shù),判斷請求類型是否跟指定的類型匹配。
-Method=GET
基于Path請求路徑的斷言工廠
PathRoutePredicateFactory:接收一個參數(shù),判斷請求的URI部分是否滿足路徑規(guī)則。
-Path=/foo/{segment}基于Query請求參數(shù)的斷言工廠
QueryRoutePredicateFactory :接收兩個參數(shù),請求param和正則表達(dá)式, 判斷請求參數(shù)是否具
有給定名稱且值與正則表達(dá)式匹配。
-Query=baz, ba.
基于路由權(quán)重的斷言工廠
WeightRoutePredicateFactory:接收一個[組名,權(quán)重], 然后對于同一個組內(nèi)的路由按照權(quán)重轉(zhuǎn)發(fā)
routes:
-id: weight_route1 uri: host1 predicates:
-Path=/product/**
-Weight=group3, 1
-id: weight_route2 uri: host2 predicates:
-Path=/product/**
-Weight= group3, 9
1.5.gateway內(nèi)置的過濾器
演示:?
后置過濾器
演示:?
前置過濾器
1.6.自定義過濾器-全局過濾器
- 認(rèn)證判斷
- 權(quán)限校驗
- 黑白名單
- 跨域配置
認(rèn)證判斷
- 當(dāng)客戶端第一次請求服務(wù)時,服務(wù)端對用戶進(jìn)行信息認(rèn)證(登錄)
- 認(rèn)證通過,將用戶信息進(jìn)行加密形成token,返回給客戶端,作為登錄憑證
- 以后每次請求,客戶端都攜帶認(rèn)證的token
- 服務(wù)端對token進(jìn)行解密,判斷是否有效。
如上圖,對于驗證用戶是否已經(jīng)登錄鑒權(quán)的過程可以在網(wǎng)關(guān)統(tǒng)一檢驗。
檢驗的標(biāo)準(zhǔn)就是請求中是否攜帶token憑證以及token的正確性。
如何定義全局過濾器:
引依賴
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.15</version> </dependency>
配置文件加入
#過濾器路徑 filter: whitePaths: #白名單路徑 - "/product/login" - "/product/aaa" blackPaths: #黑名單路徑 - "/product/bbb"
?創(chuàng)建FilterUrl黑白名單
@Component @ConfigurationProperties(prefix = "filter") public class FilterUrl { private Set<String> whitePaths=new HashSet<>(); private Set<String> blackPaths=new HashSet<>(); public Set<String> getWhitePaths() { return whitePaths; } public void setWhitePaths(Set<String> whitePaths) { this.whitePaths = whitePaths; } public Set<String> getBlackPaths() { return blackPaths; } public void setBlackPaths(Set<String> blackPaths) { this.blackPaths = blackPaths; } }
創(chuàng)建LoginFilter全局過濾器:
package com.wqg.gateway.filter; import com.alibaba.fastjson.JSON; import com.wqg.gateway.vo.FilterUrl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; /** * @ fileName:LoginFilter * @ description: * @ author:wqg * @ createTime:2023/7/17 15:23 */ @Component public class LoginFilter implements GlobalFilter , Ordered { @Autowired private FilterUrl filterUrl; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); //過濾的業(yè)務(wù)代碼 //1.獲取請求路徑 String path = request.getPath().toString(); //判斷該路徑是否放行路徑 if(filterUrl.getWhitePaths().contains(path)){ return chain.filter(exchange); } //獲取請求頭 String token = request.getHeaders().getFirst("token"); //查看redis中是否存在該token if(StringUtils.hasText(token)&&"admin".equals(token)){ //放行 return chain.filter(exchange); } //響應(yīng)json數(shù)據(jù) Map<String, Object> map = new HashMap<>(); map.put("msg", "未登錄"); map.put("code", 403); //JSON轉(zhuǎn)換 byte[] bytes = JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8); //調(diào)用bufferFactory方法,生成DataBuffer對象 DataBuffer buffer = response.bufferFactory().wrap(bytes); //調(diào)用Mono中的just方法,返回要寫給前端的JSON數(shù)據(jù) return response.writeWith(Mono.just(buffer)); } //Ordered:優(yōu)先級 值越小,優(yōu)先級越高 @Override public int getOrder() { return 0; } }
1.7.解決跨域問題
(1) 第一種寫個跨域配置類
package com.wqg.gateway.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; import org.springframework.web.util.pattern.PathPatternParser; @Configuration public class CorConfig { //處理跨域 @Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedMethod("*"); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); } }
(2)第二種跨域解決寫在配置文件中
#端口號 server: port: 81 #服務(wù)名稱 spring: application: name: qy165-gateway #配置路由轉(zhuǎn)發(fā)規(guī)則 cloud: gateway: #解決跨域 globalcors: add-to-simple-url-handler-mapping: true cors-configurations: '[/**]': #攔截的請求 allowedOrigins: #允許跨域的請求 - "*" allowedMethods: #運行跨域的請求方式 - "GET" - "POST" - "DELETE" - "PUT" - "OPTIONS" allowedHeaders: "*" #允許請求中攜帶的頭信息 allowCredentials: true #是否允許攜帶cookie maxAge: 36000 #跨域檢測的有效期,單位s routes: - id: qy165-product #路由的標(biāo)識 唯一即可 默認(rèn)按照UUID生成 uri: lb://qy165-product #真實路由轉(zhuǎn)發(fā)的地址:lb://微服務(wù)的名稱 predicates: #斷言:只要滿足斷言條件才會幫你轉(zhuǎn)發(fā)到相應(yīng)的url地址 - Path=/product/** # - After=2023-12-31T23:59:59.789+08:00[Asia/Shanghai] #要求在2023-12-31以后才可以訪問該微服務(wù) # - RemoteAddr=172.16.7.128 #只允許ip為172.16.7.128訪問 # - Header=token,\d+ # filters: # - SetStatus=250 #修改原始響應(yīng)的狀態(tài)碼 # - StripPrefix=1 - id: qy165-order uri: lb://qy165-order predicates: - Path=/order/** #指定注冊中心的地址 nacos: discovery: server-addr: localhost:8848 register-enabled: false #只拉取不注冊 #過濾器路徑 filter: whitePaths: #白名單路徑 - "/product/login" - "/product/aaa" blackPaths: #黑名單路徑 - "/product/bbb"
?上面的方案選擇一個就行
2.nginx反向代理gateway集群
2.1.配置文件
(1) nginx.conf配置
(2) 模擬gateway集群?
(3) 最后分別啟動gateway服務(wù)即可?
測試
?文章來源:http://www.zghlxwxcb.cn/news/detail-735399.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-735399.html
到了這里,關(guān)于微服務(wù)Gateway網(wǎng)關(guān)(自動定位/自定義過濾器/解決跨域)+nginx反向代理gateway集群的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!