淺析getway網(wǎng)關(guān)
一、網(wǎng)關(guān)基本概念
1、API網(wǎng)關(guān)介紹
API網(wǎng)關(guān)出現(xiàn)的原因是微服務(wù)架構(gòu)的出現(xiàn),不同的微服務(wù)一般會(huì)有不同的網(wǎng)絡(luò)地址,而外部客戶端可能需要調(diào)用多個(gè)服務(wù)的接口才能完成一個(gè)業(yè)務(wù)需求,如果讓客戶端直接與各個(gè)微服務(wù)通信,會(huì)有以下的問(wèn)題:
(1)客戶端會(huì)多次請(qǐng)求不同的微服務(wù),增加了客戶端的復(fù)雜性。
(2)存在跨域請(qǐng)求,在一定場(chǎng)景下處理相對(duì)復(fù)雜。
(3)認(rèn)證復(fù)雜,每個(gè)服務(wù)都需要獨(dú)立認(rèn)證。
(4)難以重構(gòu),隨著項(xiàng)目的迭代,可能需要重新劃分微服務(wù)。例如,可能將多個(gè)服務(wù)合并成一個(gè)或者將一個(gè)服務(wù)拆分成多個(gè)。如果客戶端直接與微服務(wù)通信,那么重構(gòu)將會(huì)很難實(shí)施。
(5)某些微服務(wù)可能使用了防火墻/瀏覽器不友好的協(xié)議,直接訪問(wèn)會(huì)有一定的困難。
以上這些問(wèn)題可以借助API網(wǎng)關(guān)解決。API網(wǎng)關(guān)是介于客戶端和服務(wù)器端之間的中間層,所有的外部請(qǐng)求都會(huì)先經(jīng)過(guò)API網(wǎng)關(guān)這一層。也就是說(shuō),API的實(shí)現(xiàn)方面更多的考慮業(yè)務(wù)邏輯,而安全、性能、監(jiān)控可以交由API網(wǎng)關(guān)來(lái)做,這樣既提高業(yè)務(wù)靈活性又不缺安全性
(6)getway可以實(shí)現(xiàn)nginx的請(qǐng)求轉(zhuǎn)發(fā)和跨域(@CrossOrigin也可以實(shí)現(xiàn)跨域)。
負(fù)載均衡:把請(qǐng)求平均分配到多臺(tái)服務(wù)器上。集群部署,部署2臺(tái)service-edu服務(wù),只有端口號(hào)不同,項(xiàng)目都一樣。
2、Spring Cloud Gateway
Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技術(shù)開(kāi)發(fā)的網(wǎng)關(guān),Spring Cloud Gateway旨在為微服務(wù)架構(gòu)提供簡(jiǎn)單、有效和統(tǒng)一的API路由管理方式,Spring Cloud Gateway作為Spring Cloud生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標(biāo)是替代Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且還基于Filer鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全、監(jiān)控/埋點(diǎn)、限流等。
網(wǎng)關(guān)和服務(wù)都在Nacos注冊(cè),注冊(cè)之后通過(guò)Getway網(wǎng)關(guān)在訪問(wèn)相應(yīng)的服務(wù)
3、Spring Cloud Gateway核心概念
網(wǎng)關(guān)提供API全托管服務(wù),豐富的API管理功能,輔助企業(yè)管理大規(guī)模的API,以降低管理成本和安全風(fēng)險(xiǎn),包括協(xié)議適配、協(xié)議轉(zhuǎn)發(fā)、安全策略、防刷、流量、監(jiān)控日志等貢呢。一般來(lái)說(shuō)網(wǎng)關(guān)對(duì)外暴露的URL或者接口信息,我們統(tǒng)稱為路由信息。如果研發(fā)過(guò)網(wǎng)關(guān)中間件或者使用過(guò)Zuul的人,會(huì)知道網(wǎng)關(guān)的核心是Filter以及Filter Chain(Filter責(zé)任鏈)。Sprig Cloud Gateway也具有路由和Filter的概念。下面介紹一下Spring Cloud Gateway中幾個(gè)重要的概念。
(1)路由。路由是網(wǎng)關(guān)最基礎(chǔ)的部分,路由信息有一個(gè)ID、一個(gè)目的URL、一組斷言和一組Filter組成。如果斷言路由為真,則說(shuō)明請(qǐng)求的URL和配置匹配
(2)斷言。Java8中的斷言函數(shù)。Spring Cloud Gateway中的斷言函數(shù)輸入類型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的斷言函數(shù)允許開(kāi)發(fā)者去定義匹配來(lái)自于http request中的任何信息,比如請(qǐng)求頭和參數(shù)等,簡(jiǎn)單來(lái)講就是一個(gè)匹配規(guī)則,如果匹配到就到Handler去處理。
(3)過(guò)濾器。一個(gè)標(biāo)準(zhǔn)的Spring webFilter。Spring cloud gateway中的filter分為兩種類型的Filter,分別是Gateway Filter和Global Filter。過(guò)濾器Filter將會(huì)對(duì)請(qǐng)求和響應(yīng)進(jìn)行修改處理,統(tǒng)一異常處理,統(tǒng)一跨域處理等。
如上圖所示,Spring cloud Gateway發(fā)出請(qǐng)求。然后再由Gateway Handler Mapping中找到與請(qǐng)求相匹配的路由,將其發(fā)送到Gateway web handler。Handler再通過(guò)指定的過(guò)濾器鏈將請(qǐng)求發(fā)送到我們實(shí)際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。
二、getway網(wǎng)關(guān)例子
1、在infrastructure模塊下創(chuàng)建api_gateway模塊
2、在pom.xml引入依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>infrastructure</artifactId> <groupId>com.stu</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>api_gateway</artifactId> <dependencies> <dependency> <groupId>com.stu</groupId> <artifactId>common-utils</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--gson--> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> <!--服務(wù)調(diào)用--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> </project>
3、編寫(xiě)application.properties配置文件
# 服務(wù)端口 server.port=8222 # 服務(wù)名 spring.application.name=service-gateway # nacos服務(wù)地址 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 #使用服務(wù)發(fā)現(xiàn)路由,通過(guò)openfeign找到服務(wù)(nginx是通過(guò)配置文件的路徑匹配發(fā)現(xiàn)服務(wù)) spring.cloud.gateway.discovery.locator.enabled=true #服務(wù)路由名小寫(xiě) #spring.cloud.gateway.discovery.locator.lower-case-service-id=true #配置service-edu服務(wù) #設(shè)置路由id(id可以隨便命名,建議用服務(wù)名稱) spring.cloud.gateway.routes[0].id=service-edu #設(shè)置路由的uri spring.cloud.gateway.routes[0].uri=lb://service-edu #設(shè)置路由斷言,代理servicerId為auth-service的/auth/路徑 spring.cloud.gateway.routes[0].predicates= Path=/eduservice/** #配置service-edu服務(wù) spring.cloud.gateway.routes[1].id=service-msm ## 服務(wù)名 #spring.application.name=service-msm spring.cloud.gateway.routes[1].uri=lb://service-msm spring.cloud.gateway.routes[1].predicates= Path=/edumsm/**
yml文件:
server: port: 8222 spring: application: cloud: gateway: discovery: locator: enabled: true routes: - id: SERVICE-ACL uri: lb://SERVICE-ACL predicates: - Path=/*/acl/** # 路徑匹配 - id: SERVICE-EDU uri: lb://SERVICE-EDU predicates: - Path=/eduservice/** # 路徑匹配 - id: SERVICE-UCENTER uri: lb://SERVICE-UCENTER predicates: - Path=/ucenter/** # 路徑匹配 nacos: discovery: server-addr: 127.0.0.1:8848
4、編寫(xiě)啟動(dòng)類
package com.stu.getway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient//Nacos注冊(cè) public class ApiGetwayApplication { public static void main(String[] args) { SpringApplication.run(ApiGetwayApplication.class,args); } }
5、測(cè)試
通過(guò)nginx配置訪問(wèn)(8001)
通過(guò)getway配置訪問(wèn)(8222)
三、網(wǎng)關(guān)相關(guān)配置
1、網(wǎng)關(guān)解決跨域問(wèn)題
(1)創(chuàng)建配置類
package com.stu.getway.config; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator; import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; import org.springframework.cloud.gateway.route.RouteDefinitionLocator; 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.codec.ServerCodecConfigurer; import org.springframework.http.codec.support.DefaultServerCodecConfigurer; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsUtils; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import org.springframework.web.util.pattern.PathPatternParser; import reactor.core.publisher.Mono; /** * <p> * 處理跨域 * </p> * * @author qy * @since 2019-11-21 */ 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; /** * description: * * @author wangpeng * @date 2019/01/02 */ @Configuration public class CorsConfig { @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、全局Filter,統(tǒng)一處理會(huì)員登錄與外部不允許訪問(wèn)的服務(wù)
package com.stu.getway.filter; import com.google.gson.JsonObject; 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.AntPathMatcher; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; import java.util.List; /** * <p> * 全局Filter,統(tǒng)一處理會(huì)員登錄與外部不允許訪問(wèn)的服務(wù) * </p> * * @author qy * @since 2019-11-21 */ @Component public class AuthGlobalFilter implements GlobalFilter, Ordered { private AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String path = request.getURI().getPath(); //校驗(yàn)用戶必須登錄 if(antPathMatcher.match("/api/**/auth/**", path)) { List<String> tokenList = request.getHeaders().get("token"); if(null == tokenList) { ServerHttpResponse response = exchange.getResponse(); return out(response); } else { // Boolean isCheck = JwtUtils.checkToken(tokenList.get(0)); // if(!isCheck) { ServerHttpResponse response = exchange.getResponse(); return out(response); // } } } //內(nèi)部服務(wù)接口,不允許外部訪問(wèn) if(antPathMatcher.match("/**/inner/**", path)) { ServerHttpResponse response = exchange.getResponse(); return out(response); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } private Mono<Void> out(ServerHttpResponse response) { JsonObject message = new JsonObject(); message.addProperty("success", false); message.addProperty("code", 28004); message.addProperty("data", "鑒權(quán)失敗"); byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8); DataBuffer buffer = response.bufferFactory().wrap(bits); //response.setStatusCode(HttpStatus.UNAUTHORIZED); //指定編碼,否則在瀏覽器中會(huì)中文亂碼 response.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); return response.writeWith(Mono.just(buffer)); } }
3、自定義異常處理
服務(wù)網(wǎng)關(guān)調(diào)用服務(wù)時(shí)可能會(huì)有一些異?;蚍?wù)不可用,它返回錯(cuò)誤信息不友好,需要我們覆蓋處理
ErrorHandlerConfig
package com.stu.getway.handler; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.reactive.error.ErrorAttributes; import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.result.view.ViewResolver; import java.util.Collections; import java.util.List; /** * 覆蓋默認(rèn)的異常處理 * * @author yinjihuan * */ @Configuration @EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class}) public class ErrorHandlerConfig { private final ServerProperties serverProperties; private final ApplicationContext applicationContext; private final ResourceProperties resourceProperties; private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public ErrorHandlerConfig(ServerProperties serverProperties, ResourceProperties resourceProperties, ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) { this.serverProperties = serverProperties; this.applicationContext = applicationContext; this.resourceProperties = resourceProperties; this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) { JsonExceptionHandler exceptionHandler = new JsonExceptionHandler( errorAttributes, this.resourceProperties, this.serverProperties.getError(), this.applicationContext); exceptionHandler.setViewResolvers(this.viewResolvers); exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters()); exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders()); return exceptionHandler; } }
JsonExceptionHandler
package com.stu.getway.handler; import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler; import org.springframework.boot.web.reactive.error.ErrorAttributes; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.web.reactive.function.server.*; import java.util.HashMap; import java.util.Map; /** * 自定義異常處理 * * <p>異常時(shí)用JSON代替HTML異常信息<p> * * @author yinjihuan * */ public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler { public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) { super(errorAttributes, resourceProperties, errorProperties, applicationContext); } /** * 獲取異常屬性 */ @Override protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) { Map<String, Object> map = new HashMap<>(); map.put("success", false); map.put("code", 20005); map.put("message", "網(wǎng)關(guān)失敗"); map.put("data", null); return map; } /** * 指定響應(yīng)處理方法為JSON處理的方法 * @param errorAttributes */ @Override protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) { return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse); } /** * 根據(jù)code獲取對(duì)應(yīng)的HttpStatus * @param errorAttributes */ @Override protected int getHttpStatus(Map<String, Object> errorAttributes) { return 200; } }
到此這篇關(guān)于getway網(wǎng)關(guān)的文章就介紹到這了,更多相關(guān)getway網(wǎng)關(guān)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解git reset --hard 和 git reset --soft區(qū)別
這篇文章主要介紹了詳解git reset --hard 和 git reset --soft區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08一文詳解VSCode安裝配置使用(最新版超詳細(xì)保姆級(jí)含插件)
安裝VScode就很簡(jiǎn)單了,一路NEXT就可以了,重點(diǎn)是配置使用以及插件推薦,這篇文章主要給大家介紹了關(guān)于VSCode安裝配置使用的相關(guān)資料,本文是最新版超詳細(xì)保姆級(jí)含插件,需要的朋友可以參考下2023-05-05前端開(kāi)發(fā)工具nvim替帶VSCode的安裝配置
這篇文章主要為大家介紹了一款前端開(kāi)發(fā)工具nvim代替VSCode的配置使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07解析動(dòng)態(tài)代理jdk的Proxy與spring的CGlib(包括區(qū)別介紹)
Spring是Java程序員基本不可能繞開(kāi)的一個(gè)框架,它的核心思想是IoC(控制反轉(zhuǎn))和AOP(面向切面編程)。本文重點(diǎn)給大家介紹動(dòng)態(tài)代理jdk的Proxy與spring的CGlib,感興趣的朋友跟隨小編一起看看吧2022-01-01關(guān)于指令重排現(xiàn)象的兩個(gè)階段詳解
這個(gè)知識(shí)點(diǎn)也是很多人說(shuō)不清道不明的地方,感覺(jué)都知道,說(shuō)又說(shuō)不出來(lái)。為什么會(huì)這樣呢?因?yàn)檫@幾個(gè)字,很容易被當(dāng)成動(dòng)詞去理解,其實(shí)正確的理解是當(dāng)成名詞,即指令重排現(xiàn)象2022-01-01對(duì)Web開(kāi)發(fā)人員有用的8個(gè)網(wǎng)站小結(jié)
本文是由比利時(shí)的Web開(kāi)發(fā)人員Jean-Baptiste Jung分享的,Jung還在《Web開(kāi)發(fā)/設(shè)計(jì)人員應(yīng)當(dāng)知道的15個(gè)網(wǎng)站》這篇文章中推薦了15個(gè)相關(guān)網(wǎng)站2011-05-05