微服务为什么一定要加 API Gateway?3 大核心价值 + 实战代码给你答案
微服务架构设计模式系列:通信篇之 API Gateway 模式
1. 为什么需要 API Gateway?
在微服务架构下,客户端要调用的服务越来越多:
- 移动端需要调用
用户服务、订单服务、支付服务 - Web 前端需要调用
商品服务、库存服务
如果客户端 直接和所有微服务交互,会带来问题:
- 客户端必须知道所有服务的地址和调用方式
- 认证、限流、监控等逻辑需要在每个服务里重复实现
- 升级接口时容易破坏客户端
API Gateway 就是为了解决这些问题:它作为 统一入口,对外屏蔽后端复杂性。
2. API Gateway 的职责
- 请求路由:根据 URL/规则,把请求转发到对应的微服务
- 聚合接口:将多个服务结果合并返回(减少客户端多次调用)
- 统一安全:认证、鉴权、Token 校验
- 流量控制:限流、熔断、降级
- 监控日志:统一采集请求日志、指标、Trace ID
3. API Gateway 的实现方式
常见的技术栈:
- Spring Cloud Gateway(Spring Boot 官方方案)
- Kong / Nginx / Traefik(独立网关)
- GraphQL Gateway(前后端数据查询优化)
下面我们以 Spring Cloud Gateway 为例。
4. 示例:Spring Cloud Gateway 配置
application.yml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/users/**
- id: order-service
uri: http://localhost:8082
predicates:
- Path=/orders/**
default-filters:
- AddRequestHeader=X-Request-Source, gateway
📌 说明:
routes:定义路由规则predicates:匹配条件(比如路径、请求头、时间段)filters:请求/响应的增强(比如加头、日志、鉴权)
聚合接口示例
比如:客户端需要 获取用户信息 + 用户订单,如果直接调用两个服务,需要请求两次。
通过 Gateway,我们可以在网关层做聚合:
@RestController
@RequestMapping("/api")
public class AggregationController {
private final WebClient webClient = WebClient.create();
@GetMapping("/user-orders/{userId}")
public Mono<Map<String, Object>> getUserAndOrders(@PathVariable Long userId) {
Mono<User> user = webClient.get().uri("http://localhost:8081/users/{id}", userId)
.retrieve().bodyToMono(User.class);
Mono<List<Order>> orders = webClient.get().uri("http://localhost:8082/orders/user/{id}", userId)
.retrieve().bodyToFlux(Order.class).collectList();
return Mono.zip(user, orders)
.map(tuple -> Map.of("user", tuple.getT1(), "orders", tuple.getT2()));
}
}
客户端只需调用一次:
GET http://gateway:8080/api/user-orders/1001
返回的数据同时包含 用户信息和订单列表。
5. API Gateway 的优缺点
优点
- 屏蔽微服务复杂性,对客户端友好
- 统一安全和流量治理
- 可以做接口聚合,减少请求次数
缺点
- 网关本身可能成为 单点瓶颈
- 增加了一次网络转发(延迟)
- 需要高可用部署和水平扩展
6. 最佳实践
- 高可用:网关部署多副本,配合负载均衡
- 鉴权前置:所有请求先过网关,减少服务端负担
- 监控埋点:在网关层采集请求日志和指标
- 灰度发布:通过网关的路由规则实现流量分流
✅ 总结
API Gateway 是微服务架构通信层的核心模式,它不仅仅是一个 路由器,更是 安全、流量、聚合、监控的中枢。
在实际项目里,常见做法是:
- 外部请求 → API Gateway
- 内部服务调用 → 服务发现(如 Eureka、Consul)
基于 Spring Cloud Gateway 的项目实战
🏗️ 一、项目结构
microservices-demo/
├── gateway-service/ # API Gateway
│ ├── src/main/java/com/example/gateway/
│ │ └── GatewayApplication.java
│ └── src/main/resources/application.yml
│
├── user-service/ # 用户服务
│ ├── src/main/java/com/example/user/
│ │ └── UserApplication.java
│ └── src/main/resources/application.yml
│
└── order-service/ # 订单服务
├── src/main/java/com/example/order/
│ └── OrderApplication.java
└── src/main/resources/application.yml
📦 二、依赖配置
gateway-service/pom.xml
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Spring Cloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Redis (限流、缓存等需要) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Actuator for monitoring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
⚙️ 三、网关配置 (application.yml)
gateway-service/src/main/resources/application.yml
server:
port: 8080 # 网关对外端口
spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
enabled: false # 可以启用服务发现模式(比如配合 Eureka)
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/users/**
filters:
- StripPrefix=0 # 1 去掉 /users 前缀,转发到 user-service
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 # 每秒新增 5 个令牌
redis-rate-limiter.burstCapacity: 1 # 短时突发最大 10
key-resolver: "#{@ipKeyResolver}"
- id: order-service
uri: http://localhost:8082
predicates:
- Path=/orders/**
filters:
- StripPrefix=0
default-filters:
- AddRequestHeader=X-Request-Source, gateway
data:
redis:
host: localhost
port: 6379
management:
endpoints:
web:
exposure:
include: health,info,gateway
📌 配置说明:
id:路由的唯一 IDuri:后端服务地址(可以是http://,也可以是lb://service-name)predicates:路由条件,这里用Path匹配 URLfilters:请求/响应过滤器(去掉前缀、增加 header 等)default-filters:所有路由生效
⚠️ 注意:
Spring Cloud Gateway 的 RequestRateLimiter 默认使用 Redis 存储令牌桶。
所以需要在 application.yml 里配置 Redis 连接,比如:
spring:
data:
redis:
host: localhost
port: 6379
📌 运行效果
- 所有请求先走
http://localhost:8080(Gateway)。 /users/**→ 转发到userservice (8081),限流 5 req/s,突发 10。/orders/**→ 转发到orderservice (8082),限流 2 req/s,突发 5。- 限流策略基于客户端 IP。
🛡️ 四、自定义全局过滤器和RequestRateLimiter
例如我们希望 记录所有请求日志:
gateway-service/src/main/java/com/example/gateway/filter/LoggingFilter.java
@Component
public class LoggingFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(LoggingFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
log.info("Incoming request: {}", path);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 优先级,数字越小越先执行
}
}
自定义 KeyResolver
默认的 RequestRateLimiter 需要 key-resolver,我们用客户端 IP 作为 key,保证每个 IP 独立限流。
src/main/java/com/example/gateway/config/RateLimiterConfig.java
package com.example.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
@Configuration
public class RateLimiterConfig {
/**
* 使用客户端 IP 作为限流 Key
*/
@Bean
public KeyResolver ipKeyResolver() {
return exchange ->
Mono.just(exchange.getRequest()
.getRemoteAddress()
.getAddress()
.getHostAddress());
}
}
启动类
src/main/java/com/example/gateway/GatewayApplication.java
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
👤 五、用户服务配置
user-service/src/main/resources/application.yml
server:
port: 8081
spring:
application:
name: user-service
user-service/src/main/java/com/example/user/UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public Map<String, Object> getUser(@PathVariable Long id) {
return Map.of("id", id, "name", "User-" + id);
}
}
📦 六、订单服务配置
order-service/src/main/resources/application.yml
server:
port: 8082
spring:
application:
name: order-service
order-service/src/main/java/com/example/order/OrderController.java
@RestController
@RequestMapping("/orders")
public class OrderController {
@GetMapping("/user/{userId}")
public List<Map<String, Object>> getOrders(@PathVariable Long userId) {
return List.of(
Map.of("orderId", 1001, "userId", userId, "item", "Laptop"),
Map.of("orderId", 1002, "userId", userId, "item", "Phone")
);
}
}
🔗 七、调用示例
- 请求用户信息
GET http://localhost:8080/users/1
➡️ 网关转发到 http://localhost:8081/users/1
- 请求订单信息
GET http://localhost:8080/orders/user/1
➡️ 网关转发到 http://localhost:8082/orders/user/1
- 统一请求头
X-Request-Source: gateway
由 default-filters 自动添加。
✅ 至此,我们已经有一个 完整可运行的 API Gateway 配置,包括:
gateway-service:路由 & 过滤器user-service:简单用户 APIorder-service:简单订单 API
更多推荐



所有评论(0)