目录
温馨提示:全套教程请查看 教程总览
前提条件
需要先下载 Nacos 并启动 Nacos server。操作步骤参见 2 - 服务注册与发现组件 —— Nacos的安装
一、简介
Gateway 是在Spring生态系统之上构建的API网关服务,基于Spring6,Spring Boot 3和Project Reactor等技术。它旨在为微服务架构提供一种简单有效的、统一的 API 路由管理方式,并为它们提供跨领域的关注点,例如:安全性、监控/指标和容错能力。
如何引入Spring Cloud Gateway
如果要在我们的项目中使用 Spring Cloud Gateway,请使用 group ID 为 org.springframework.cloud
,artifact ID 为 spring-cloud-starter-gateway
的starter。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
如果你添加了 starter,但你不希望启用网关,请设置 spring.cloud.gateway.enabled=false
。
术语表
-
Route(路由): 网关的基本构件。它由一个ID、一个目的地URI、一个断言(Predicate)集合和一个过滤器(Filter)集合定义。如果断言为
true
,则路由被匹配。 -
Predicate(断言): 这是一个 Java 8 Function Predicate。输入类型是
Spring Framework ServerWebExchange
。这让你可以在HTTP请求中的任何内容上进行匹配,比如header或查询参数。 -
Filter(过滤器): 这些是 GatewayFilter 的实例,已经用特定工厂构建。在这里,你可以在发送下游请求之前或之后修改请求和响应。
工作流程
- 客户端向 Spring Cloud Gateway 发出请求。
- Spring Cloud Gateway 在
Gateway Handler Mapping
中找到与请求相匹配的路由,将其发送到Gateway Web Handler
。 Gateway Web Handler
再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回结果。- Filter(过滤器)之间用虚线分开是因为过滤器可能会在发送代理请求之前(pre)或之后(post)执行业务逻辑。
- 在“pre”(前)类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等业务逻辑;
- 在“post”(后)类型的过滤器中可以做响应内容、响应头的修改、日志的输出、流量监控等业务逻辑。
Spring Cloud Gateway 组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。
Spring Cloud Gateway 是加在整个微服务最前沿的防火墙和代理器,隐藏微服务结点的IP、端口信息,从而加强安全保护。
Spring Cloud Gateway 本身也是一个微服务,需要注册进服务注册中心。
参考文档 请查看 官网
二、搭建Gateway应用
1.创建项目
1.1 新建Module
1.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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.ash</groupId>
<artifactId>spring-cloud-alibaba-demo</artifactId>
<version>${revision}</version>
</parent>
<artifactId>cloud-gateway</artifactId>
<description>gateway网关</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- gateway网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Nacos注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Nacos配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- bootstrap配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- loadbalancer负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<!-- 将源码中的xml文件打包到jar中 -->
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>
2.添加启动类
新建启动类 GatewayApplication.java
内容如下:
package org.ash.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3.添加配置文件
resources目录下新建 application.yml
配置文件,内容如下:
server:
port: 9000
spring:
application:
# 服务名称
name: cloud-gateway
cloud:
nacos:
# nacos注册中心
discovery:
# 服务ip:port
server-addr: 127.0.0.1:8848
# 路由网关配置
gateway:
# 设置与服务注册发现组件结合,这样可以采用服务名的路由策略
discovery:
locator:
enabled: true
routes:
# 服务提供者
- id: id-cloud-provider # 路由id,唯一
# 采用 LoadBalanceClient 方式请求,以 lb:// 开头,后面的是注册在 Nacos 上的服务名
uri: lb://cloud-provider
predicates: # 路由断言
# - Path=/provider/** # 路由匹配规则
- Method=GET,POST,PUT,DELETE
# 服务消费者
- id: id-cloud-consumer-feign
uri: lb://cloud-consumer-feign
predicates:
# - Path=/consumer-feign/**
- Method=GET,POST,PUT,DELETE
management:
endpoints:
web:
exposure:
include: '*'
三、运行测试
1.启动项目
1.1 启动gateway服务
1.2 启动服务提供者
1.3 启动服务消费者
2.查看Nacos控制台
打开浏览器访问:http://localhost:8848/nacos
,并打开控制台 “服务管理” 下的 “服务列表” 页面,看到 cloud-gateway
服务、cloud-provider
服务和 cloud-consumer-feign
已经注册进Nacos,表示服务注册成功。
3.调用测试接口
打开浏览器,我们通过 cloud-gateway
服务的 9000
端口调用 cloud-consumer-feign
服务测试接口 http://localhost:9000/cloud-consumer-feign/consumer/feign/test/open-feign
,成功返回消息,表示调用成功。
配置文件中
predicates(断言)
规则中的Path
属性我这边注释了,大家下去也可以给cloud-provider
服务和cloud-consumer-feign
服务添加server.servlet.context-path
属性,然后通过配置 Path 路由匹配规则来做不同服务之间的接口转发。
这样配置之后,上面的测试接口http://localhost:9000/cloud-consumer-feign/consumer/feign/test/open-feign
中的服务名称就不用写了,直接用各个服务的server.servlet.context-path
就可以了。
四、全局过滤
GlobalFilter
全局过滤器是Gateway默认已有的,不需要任何配置,直接实现 GlobalFilter
接口即可,作用于所有路由,可以用来做权限认证、接口访问统计等。
1.添加全局过滤器
新建 MyGlobalFilter.java
,并实现 GlobalFilter, Ordered
这两个接口
内容如下:
package org.ash.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return null;
}
@Override
public int getOrder() {
return 0;
}
}
这里我们用自定义的全局过滤器 MyGlobalFilter
记录接口的请求信息和请求耗时,内容如下:
package org.ash.gateway.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Slf4j
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
/**
* 开始访问时间
*/
private static final String BEGIN_REQUEST_TIME = "begin_request_time";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 记录请求接口的开始时间
exchange.getAttributes().put(BEGIN_REQUEST_TIME, System.currentTimeMillis());
return chain.filter(exchange).then(Mono.fromRunnable(()->{
Long beginRequestTime = exchange.getAttribute(BEGIN_REQUEST_TIME);
if (beginRequestTime != null){
log.info("请求接口IP: " + exchange.getRequest().getURI().getHost());
log.info("请求接口PORT: " + exchange.getRequest().getURI().getPort());
log.info("请求接口URL: " + exchange.getRequest().getURI().getPath());
log.info("请求接口URL参数: " + exchange.getRequest().getURI().getRawQuery());
log.info("请求接口时长: " + (System.currentTimeMillis() - beginRequestTime) + "ms");
}
}));
}
@Override
public int getOrder() {
// 数字越小优先级越高
return 0;
}
}
2.测试
重新启动 cloud-gateway
服务,然后调用测试接口 http://localhost:9000/cloud-consumer-feign/consumer/feign/test/open-feign
,查看控制台输出
由此可见,Gateway自定义全局过滤器生效。
更多Gateway过滤器请查看 官网详情
至此,Spring Cloud Gateway网关搭建完成!!!
温馨提示:全套教程请查看 教程总览