淺析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ù)一般會有不同的網(wǎng)絡(luò)地址,而外部客戶端可能需要調(diào)用多個服務(wù)的接口才能完成一個業(yè)務(wù)需求,如果讓客戶端直接與各個微服務(wù)通信,會有以下的問題:
(1)客戶端會多次請求不同的微服務(wù),增加了客戶端的復(fù)雜性。
(2)存在跨域請求,在一定場景下處理相對復(fù)雜。
(3)認證復(fù)雜,每個服務(wù)都需要獨立認證。
(4)難以重構(gòu),隨著項目的迭代,可能需要重新劃分微服務(wù)。例如,可能將多個服務(wù)合并成一個或者將一個服務(wù)拆分成多個。如果客戶端直接與微服務(wù)通信,那么重構(gòu)將會很難實施。
(5)某些微服務(wù)可能使用了防火墻/瀏覽器不友好的協(xié)議,直接訪問會有一定的困難。
以上這些問題可以借助API網(wǎng)關(guān)解決。API網(wǎng)關(guān)是介于客戶端和服務(wù)器端之間的中間層,所有的外部請求都會先經(jīng)過API網(wǎng)關(guān)這一層。也就是說,API的實現(xiàn)方面更多的考慮業(yè)務(wù)邏輯,而安全、性能、監(jiān)控可以交由API網(wǎng)關(guān)來做,這樣既提高業(yè)務(wù)靈活性又不缺安全性
(6)getway可以實現(xiàn)nginx的請求轉(zhuǎn)發(fā)和跨域(@CrossOrigin也可以實現(xiàn)跨域)。

負載均衡:把請求平均分配到多臺服務(wù)器上。集群部署,部署2臺service-edu服務(wù),只有端口號不同,項目都一樣。

2、Spring Cloud Gateway
Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技術(shù)開發(fā)的網(wǎng)關(guān),Spring Cloud Gateway旨在為微服務(wù)架構(gòu)提供簡單、有效和統(tǒng)一的API路由管理方式,Spring Cloud Gateway作為Spring Cloud生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標是替代Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且還基于Filer鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全、監(jiān)控/埋點、限流等。

網(wǎng)關(guān)和服務(wù)都在Nacos注冊,注冊之后通過Getway網(wǎng)關(guān)在訪問相應(yīng)的服務(wù)

3、Spring Cloud Gateway核心概念
網(wǎng)關(guān)提供API全托管服務(wù),豐富的API管理功能,輔助企業(yè)管理大規(guī)模的API,以降低管理成本和安全風險,包括協(xié)議適配、協(xié)議轉(zhuǎn)發(fā)、安全策略、防刷、流量、監(jiān)控日志等貢呢。一般來說網(wǎng)關(guān)對外暴露的URL或者接口信息,我們統(tǒng)稱為路由信息。如果研發(fā)過網(wǎng)關(guān)中間件或者使用過Zuul的人,會知道網(wǎng)關(guān)的核心是Filter以及Filter Chain(Filter責任鏈)。Sprig Cloud Gateway也具有路由和Filter的概念。下面介紹一下Spring Cloud Gateway中幾個重要的概念。
(1)路由。路由是網(wǎng)關(guān)最基礎(chǔ)的部分,路由信息有一個ID、一個目的URL、一組斷言和一組Filter組成。如果斷言路由為真,則說明請求的URL和配置匹配
(2)斷言。Java8中的斷言函數(shù)。Spring Cloud Gateway中的斷言函數(shù)輸入類型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的斷言函數(shù)允許開發(fā)者去定義匹配來自于http request中的任何信息,比如請求頭和參數(shù)等,簡單來講就是一個匹配規(guī)則,如果匹配到就到Handler去處理。
(3)過濾器。一個標準的Spring webFilter。Spring cloud gateway中的filter分為兩種類型的Filter,分別是Gateway Filter和Global Filter。過濾器Filter將會對請求和響應(yīng)進行修改處理,統(tǒng)一異常處理,統(tǒng)一跨域處理等。

如上圖所示,Spring cloud Gateway發(fā)出請求。然后再由Gateway Handler Mapping中找到與請求相匹配的路由,將其發(fā)送到Gateway web handler。Handler再通過指定的過濾器鏈將請求發(fā)送到我們實際的服務(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、編寫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)路由,通過openfeign找到服務(wù)(nginx是通過配置文件的路徑匹配發(fā)現(xiàn)服務(wù)) spring.cloud.gateway.discovery.locator.enabled=true #服務(wù)路由名小寫 #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:88484、編寫啟動類
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注冊
public class ApiGetwayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGetwayApplication.class,args);
}
}5、測試
通過nginx配置訪問(8001)

通過getway配置訪問(8222)

三、網(wǎng)關(guān)相關(guān)配置
1、網(wǎng)關(guā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)一處理會員登錄與外部不允許訪問的服務(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)一處理會員登錄與外部不允許訪問的服務(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();
//校驗用戶必須登錄
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ù)接口,不允許外部訪問
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);
//指定編碼,否則在瀏覽器中會中文亂碼
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ù)時可能會有一些異常或服務(wù)不可用,它返回錯誤信息不友好,需要我們覆蓋處理
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;
/**
* 覆蓋默認的異常處理
*
* @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>異常時用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獲取對應(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解git reset --hard 和 git reset --soft區(qū)別
這篇文章主要介紹了詳解git reset --hard 和 git reset --soft區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-08-08
一文詳解VSCode安裝配置使用(最新版超詳細保姆級含插件)
安裝VScode就很簡單了,一路NEXT就可以了,重點是配置使用以及插件推薦,這篇文章主要給大家介紹了關(guān)于VSCode安裝配置使用的相關(guān)資料,本文是最新版超詳細保姆級含插件,需要的朋友可以參考下2023-05-05
解析動態(tài)代理jdk的Proxy與spring的CGlib(包括區(qū)別介紹)
Spring是Java程序員基本不可能繞開的一個框架,它的核心思想是IoC(控制反轉(zhuǎn))和AOP(面向切面編程)。本文重點給大家介紹動態(tài)代理jdk的Proxy與spring的CGlib,感興趣的朋友跟隨小編一起看看吧2022-01-01
對Web開發(fā)人員有用的8個網(wǎng)站小結(jié)
本文是由比利時的Web開發(fā)人員Jean-Baptiste Jung分享的,Jung還在《Web開發(fā)/設(shè)計人員應(yīng)當知道的15個網(wǎng)站》這篇文章中推薦了15個相關(guān)網(wǎng)站2011-05-05

