-
背景
-
SpringCloud Gateway 简介
-
Gateway入门搭建
-
1. 创建一个SpringBoot 项目
-
2. 添加依赖
-
3. 配置路由转发
-
4. 添加请求`log` `Filter`
-
5. 搭建测试服务
-
测试
背景
接上次线上Spring Boot 和Spring Cloud、Spring Cloud Alibaba版本如何选择以及Zuul和Gateway请求IO模型比对(WebFlux优势)以及Reactor模型分析
选定微服务中网关使用Gateway
,接下来我们先搭建一个简单的网关使用
SpringCloud Gateway 简介
github地址: https://github.com/spring-cloud/spring-cloud-gateway
官网文档地址: https://spring.io/projects/spring-cloud-gateway#learn
SpringCloud Gateway
是 Spring Cloud
的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
SpringCloud Gateway
作为 Spring Cloud
生态系统中的网关,目标是替代 Zuul
,在Spring Cloud 2.0
以上版本中,没有对新版本的Zuul 2.0
以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0
之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway
是基于WebFlux
框架实现的,而WebFlux
框架底层则使用了高性能的Reactor模式通信框架Netty。
说人话为什么需要网关呢?我们来想想没有网关我们有多个服务需要做什么?
首先我们的客户端流量入口调用之间的关系可能是这样的

这样会存在什么问题呢?
-
如果添加鉴权功能,需要对每一个服务进行改造 -
跨域问题需要对每一个服务进行改造 -
跨域问题需要对每一个服务进行改造 -
灰度发布、动态路由需要对每一个服务进行改造 -
存在安全问题。每个微服务暴露的 Endpoint是固定的,客户端访问需要清楚各个微服务真实的Endpoint
如果我们在服务前添加一层网关作为所有流量的入库,整个架构就变成如下方式

然后上面所有的问题都可以在网关统一实现,各个服务就无需再实现
Gateway入门搭建
1. 创建一个SpringBoot 项目
2. 添加依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wh</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>gateway</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-gateway-spring-boot-starter </artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. 配置路由转发
-
Application.yml
server:
port: 8080
spring:
application:
name: gate-way
cloud:
gateway:
routes:
- id: plutus_route
uri: http://localhost:10080
predicates:
- Path=/plutus/**
这里简单的配置了一下网关的启动端口为8080
,然后配置了一个路由规则
这里配置的路由规则就是 拦截所有请求路径前缀为/plutus
然后转发到http://localhost:10080
路径
举个简单例子:
我这里访问网关的url为
localhost:8080/plutus/finance/v1/bill/exception
那么实际的访问url就会被转发到
http://localhost:10080/plutus/finance/v1/bill/exception
4. 添加请求log
Filter
@Slf4j
@Component
@AllArgsConstructor
public class RequestLogFilter implements GlobalFilter, Ordered {
private static final String START_TIME = "startTime";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String requestUrl = exchange.getRequest().getURI().getRawPath();
// 构建成一条长 日志,避免并发下日志错乱
StringBuilder beforeReqLog = new StringBuilder(300);
// 日志参数
List<Object> beforeReqArgs = new ArrayList<>();
beforeReqLog.append("nn================ Cider Gateway Request Start ================n");
// 打印路由
beforeReqLog.append("===> {}: {}n");
// 参数
String requestMethod = exchange.getRequest().getMethodValue();
beforeReqArgs.add(requestMethod);
beforeReqArgs.add(requestUrl);
// 打印请求头
HttpHeaders headers = exchange.getRequest().getHeaders();
headers.forEach((headerName, headerValue) -> {
beforeReqLog.append("===Headers=== {}: {}n");
beforeReqArgs.add(headerName);
beforeReqArgs.add(StringUtils.collectionToCommaDelimitedString(headerValue));
});
beforeReqLog.append("================ Cider Gateway Request End =================n");
// 打印执行时间
log.info(beforeReqLog.toString(), beforeReqArgs.toArray());
exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
Long startTime = exchange.getAttribute(START_TIME);
long executeTime = 0L;
if (startTime != null) {
executeTime = (System.currentTimeMillis() - startTime);
}
// 构建成一条长 日志,避免并发下日志错乱
StringBuilder responseLog = new StringBuilder(300);
// 日志参数
List<Object> responseArgs = new ArrayList<>();
responseLog.append("nn================ Cider Gateway Response Start ================n");
// 打印路由 200 get: /mate*/xxx/xxx
responseLog.append("<=== {} {}: {}: {}n");
// 参数
responseArgs.add(response.getStatusCode().value());
responseArgs.add(requestMethod);
responseArgs.add(requestUrl);
responseArgs.add(executeTime + "ms");
// 打印请求头
HttpHeaders httpHeaders = response.getHeaders();
httpHeaders.forEach((headerName, headerValue) -> {
responseLog.append("===Headers=== {}: {}n");
responseArgs.add(headerName);
responseArgs.add(StringUtils.collectionToCommaDelimitedString(headerValue));
});
responseLog.append("================ Cider Gateway Response End =================n");
// 打印执行时间
log.info(responseLog.toString(), responseArgs.toArray());
}));
}
@Override
public int getOrder() {
return 0;
}
}
5. 搭建测试服务
这里我们搭建一个简单的plutus
服务,一个简单的SpringBoot
项目
配置文件
server:
port: 10080
servlet:
context-path: /plutus
然后在写一个简单的接口
@RestController
@RequestMapping("/finance/v1")
@Slf4j
public class FinanceController {
@GetMapping("/bill/exception")
public String getFinanceExceptionVO() {
System.out.println("路由转发成功");
return "SUCCESS";
}
}
测试
我们访问
localhost:8080/plutus/finance/v1/bill/exception

我们在plutus
项目的控制台可以看到输出路由转发成功,代表请求转发成功了

同时我们也能看到网关打印出了请求log

原文始发于微信公众号(小奏技术):最新版本SpringCloud Gateway网关入门(一)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/30188.html