文章目录
spring cloud gateway 入门篇
1. 添加依赖。创建springboot项目,添加相关依赖,启动项目
创建一个空的springboot项目
步骤:略
pom配置
通过配置 spring.cloud.gateway.enabled=false
可以关闭网关功能
<!-- 后续文章都基于此版本号 -->
<properties>
<java.version>17</java.version>
<spring-boot.version>3.2.4</spring-boot.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
</properties>
<!-- 统一管理依赖版本号 -->
<dependencyManagement>
<dependencies>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- SpringCloud-Gateway 网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
2. 核心概念
- Route(路由): 网关的基本构件。它由一个ID、一个目的地URI、一个谓词(Predicate)集合和一个过滤器(Filter)集合定义。如果集合谓词为真,则路由被匹配。
- Predicate(断言): 这是一个 Java 8 Function Predicate。Spring Framework
ServerWebExchange
。这让你可以在HTTP请求中的任何内容上进行匹配,比如header或查询参数。 - Filter(过滤器): 这些是
GatewayFilter
的实例,已经用特定工厂构建。在这里,你可以在发送下游请求之前或之后修改请求和响应。
过滤器逻辑都被执行。然后发出代理请求。在代理请求发出后,"post"
(后)过滤器逻辑被运行。
4.配置路由
一、通过 .yml 或者 .properties 文件配置
server:
port: 8080
spring:
application:
name: gateway-demo
cloud:
# Gateway 配置
gateway:
# 为所有路由配置Http超时(响应和连接)
httpclient:
connect-timeout: 3000
response-timeout: 3s
# 路由集合
routes:
# 路由id,唯一即可。建议配合服务名
- id: my-route-id-1
# 断言配置。当请求满足断言时,路由才会生效。若配置了多个断言,需要同时满足所有断言才生效
predicates:
- Path=/order-service/** # 按照path路径进行匹配,只要以/order-service/开头就符合规则
# 路由的目的地,匹配后提供服务的路由地址。可以配合nacos通过服务名自动负载均衡
uri: http://127.0.0.1:7777
# 路由优先级。匹配到多个路由,最小的执行
order: 1
# 过滤器配置。系统内置多个网关过滤器,也
filters:
- StripPrefix=1 # 内置过滤器:表示截断路径前缀。如果请求的路径为/order-service/order/1,则路径会修改为/order/1
- AddRequestParameter=tenantId, 123456 # 内置过滤器:表示给当前路由加上查询参数 ?tenantId=123456
# 路由Http超时配置
metadata:
response-timeout: 200
connect-timeout: 200
- id: my-route-id-2
predicates:
- Path=/user-service/**
uri: http://127.0.0.1:8888
filters:
- StripPrefix=1
- id: my-route-id-3
predicates:
- Path=/dict-service/**
uri: http://127.0.0.1:9999
filters:
- StripPrefix=1
二、也可以通过 Route 的Fluent式 Java API 方式配置
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
return builder.routes()
.route(r -> r.host("**.abc.org").and().path("/image/png")
.filters(f -> f.addResponseHeader("X-TestHeader", "foobar"))
.uri("http://httpbin.org:80")
)
.route(r -> r.path("/image/webp")
.filters(f -> f.addResponseHeader("X-AnotherHeader", "baz"))
.uri("http://httpbin.org:80")
.metadata("key", "value")
)
.route(r -> r.order(-1)
.host("**.throttle.org").and().path("/get")
.filters(f -> f.filter(throttle.apply(1, 1, 10, TimeUnit.SECONDS)))
.uri("http://httpbin.org:80")
.metadata("key", "value")
)
.build();
}
5.在本地准备另外一个简单的web项目(order-service),启动端口7777
server:
port: 8080
并准备几个简单的测试接口
@Slf4j @RestController
public class OrderController {
@PostMapping("/order/add")
public CommResponse addOrder(@Validated @RequestBody Order order) {
log.info("Micro Order Add!order={}", order);
var response = new CommResponse();
response.setRespCode("2000");
response.setRespMsg("Success");
response.setRespData("Micro Order Add Success");
log.info("Micro Order Add Success!response={}", response);
return response;
}
@PostMapping("/order/simulation")
public void addSimulation() {
log.info("Micro Order simulation!模拟网络延迟");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@GetMapping("/order/list")
public CommResponse orderList(@RequestParam(value = "tenantId") String tenantId) {
log.info("Micro Order List!tenantId={}", tenantId);
var response = new CommResponse();
response.setRespCode("2000");
response.setRespMsg("Success");
response.setRespData(Order.init());
return response;
}
@GetMapping("/order/{id}")
public CommResponse getOrder(@PathVariable(name = "id") String id) {
log.info("Get Order By ID!id={}", id);
var response = new CommResponse();
response.setRespCode("2000");
response.setRespMsg("Success");
response.setRespData(Order.init().stream().filter(order -> order.getId().equals(id)).findFirst().orElse(null));
return response;
}
}
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString
public class Order {
private String id;
private String name;
private List<String> productList;
private String createTime;
public static List<Order> init() {
List<Order> orderList = new ArrayList<>();
orderList.add(new Order("1", "水果店订单", Arrays.asList("苹果", "梨"), "2024-10-12 10:12:00"));
orderList.add(new Order("2", "洗衣液1kg订单", Arrays.asList("洗衣液"), "2024-10-15 20:12:00"));
orderList.add(new Order("3", "杯子订单", Arrays.asList("保温杯", "马克杯", "吸管杯"), "2024-10-18 12:30:00"));
return orderList;
}
}
@Data
public class CommResponse {
private String respCode;
private String respMsg;
private Object respData;
}
启动测试启动
- 本地启动Gateway项目(8080)
- 本地启动Order项目(7777)
- 本地启动路由配置中相关的其它测试项目…
使用apiPost、postMan等工具进行接口调用测试
post: http://127.0.0.1:8080/order-service/order/add
post: http://127.0.0.1:8080/order-service/order/simulation
get: http://127.0.0.1:8080/order-service/order/list
get: http://127.0.0.1:8080/order-service/order/1
...