摘要钩子:微服务架构中,几十个服务散落各处,接口调用混乱不堪?一个简单的用户请求要在十几个服务间跳转?是时候用一个统一的API网关来终结这种混乱了!本文带你从零构建一个基于FastAPI的企业级API网关,实现服务发现、动态路由、负载均衡、熔断限流等核心功能。通过3000+行实战代码,你将掌握微服务架构的核心枢纽技术,打造高可用、易维护的分布式系统!
开篇:微服务架构的"交通警察"为什么必不可少?
最近和一家电商公司的架构师朋友聊天,他们刚经历了微服务拆分后的"阵痛期":原本单体应用拆成了32个微服务,结果发现新的问题更多了——
- 客户端调用混乱:前端需要对接十几个不同服务的接口地址
- 认证授权分散:每个服务都要重复实现用户验证逻辑
- 监控困难:问题发生时,难以追踪完整的请求链路
- 性能瓶颈:没有统一的限流熔断,一个服务挂掉会拖垮整个系统
这就像一个大城市没有交通信号灯,每个路口都堵成一团。而API网关就是这个城市的"交通警察",它站在所有微服务的前端,统一处理所有入口流量,让系统变得井然有序。
先看一个真实案例:某在线教育平台,微服务化后接口响应时间从平均50ms暴涨到200ms。引入API网关后,通过智能路由和缓存优化,响应时间降低到70ms,同时系统可用率从99.5%提升到99.95%。这就是API网关的价值!
如果你正在规划或已经实施了微服务架构,却苦于如何管理这"散落一地"的服务,那么这篇文章就是为你准备的。我们将手把手构建一个功能完整的API网关,让你不仅理解理论,更能亲手实践。
第一部分:项目规划与架构设计
1.1 需求分析:企业级API网关需要哪些功能?
在开始编码之前,我们先明确API网关的核心职责:
- 路由转发:将客户端请求正确转发到后端服务
- 负载均衡:在多实例间分配请求,提高系统吞吐量
- 服务发现:动态感知后端服务的上线和下线
- 认证授权:统一验证用户身份,避免每个服务重复实现
- 限流熔断:防止雪崩效应,保证系统稳定性
- 日志监控:记录完整请求链路,便于问题排查
- 缓存优化:对热点数据进行缓存,减少后端压力
1.2 技术选型:为什么选择FastAPI?
2025年的微服务架构中,API网关有多种技术选择,我们选择FastAPI的原因:
技术方案
优势
劣势
适用场景
FastAPI
异步高性能,自动文档,类型安全
生态相对年轻
高并发API网关
Spring Cloud Gateway
Java生态完整,功能丰富
内存消耗大,启动慢
大型企业Java技术栈
Nginx + Lua
性能极致,稳定可靠
开发门槛高,调试困难
超大规模流量入口
Kong
功能全面,插件丰富
资源占用多,配置复杂
需要丰富插件支持
FastAPI的优势在于:
- 异步非阻塞:单机即可支持数万并发连接
- 自动文档:OpenAPI自动生成,调试方便
- 类型安全:Pydantic保证数据格式正确性
- 易于扩展:中间件机制灵活,可快速添加新功能
1.3 系统架构设计
我们的API网关将采用分层架构:
┌─────────────────────────────────────────┐
│ 客户端请求 │
└─────────────────┬───────────────────────┘
│
┌───────▼────────┐
│ API网关入口 │ ←─ 认证、限流、日志
│ (FastAPI) │
└───────┬────────┘
│
┌───────▼────────┐
│ 路由引擎 │ ←─ 服务发现、负载均衡
│ │
└───────┬────────┘
│
┌───────▼────────┐
│ 代理转发 │ ←─ 请求改写、响应处理
│ │
└───────┬────────┘
│
┌───────▼────────┐
│ 后端微服务 │
│ (User/Order/...)│
└─────────────────┘
1.4 项目结构规划
创建清晰的项目结构是保持代码可维护性的关键:
api-gateway/
├── app/
│ ├── __init__.py
│ ├── main.py # 应用入口
│ ├── config.py # 配置管理
│ ├── database.py # 数据库连接(用于存储路由规则)
│ ├── models.py # 数据模型
│ ├── schemas.py # Pydantic模型
│ ├── dependencies.py # 依赖注入
│ ├── middleware.py # 中间件(认证、限流、日志)
│ ├── routers/
│ │ ├── __init__.py
│ │ ├── gateway.py # 网关路由入口
│ │ └── admin.py # 管理接口
│ ├── services/
│ │ ├── __init__.py
│ │ ├── router.py # 路由引擎
│ │ ├── discovery.py # 服务发现
│ │ ├── load_balancer.py # 负载均衡
│ │ ├── auth.py # 认证服务
│ │ └── circuit_breaker.py # 熔断器
│ ├── utils/
│ │ ├── __init__.py
│ │ ├── logger.py # 日志工具
│ │ └── cache.py # 缓存工具
│ └── clients/
│ ├── __init__.py
│ └── http_client.py # HTTP客户端
├── tests/ # 测试代码
├── docker-compose.yml # Docker编排
├── Dockerfile # Docker镜像
├── requirements.txt # Python依赖
└── README.md # 项目说明
现在开始搭建基础环境。
第二部分:环境搭建与基础框架
2.1 一键安装与验证
我们提供三种安装方式,满足不同开发者的需求:
方式一:使用uv(2025年最快的包管理工具)
# 安装uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# 创建项目目录
mkdir api-gateway && cd api-gateway
# 创建虚拟环境并安装依赖
uv venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
uv pip install -r requirements.txt
方式二:传统pip方式
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install --upgrade pip
pip install -r requirements.txt
方式三:Docker快速启动
# 克隆项目
git clone <your-repo>
cd api-gateway
# 启动所有服务
docker-compose up -d
安装完成后,验证FastAPI版本:
python -c "import fastapi; print(f'FastAPI版本: {fastapi.__version__}')"
2.2 配置管理:环境变量与配置文件分离
在企业级项目中,配置管理至关重要。我们采用三层配置策略:
- 环境变量:最敏感的信息(数据库密码、API密钥)
- 配置文件:环境相关的配置(数据库地址、Redis地址)
- 代码默认值:开发环境的默认配置
创建 app/config.py:
# app/config.py
from pydantic import Field
from pydantic_settings import BaseSettings
from typing import Optional, List
import os
class Settings(BaseSettings):
"""应用配置"""
# 应用配置
app_name: str = "API Gateway"
app_version: str = "1.0.0"
debug: bool = False
# 服务配置
host: str = "0.0.0.0"
port: int = 8000
# 数据库配置
database_url: str = Field(
default="postgresql://postgres:password@localhost:5432/api_gateway",
env="DATABASE_URL"
)
# Redis配置
redis_url: str = Field(
default="redis://localhost:6379/0",
env="REDIS_URL"
)
# 认证配置
secret_key: str = Field(
default="your-secret-key-change-in-production",
env="SECRET_KEY"
)
algorithm: str = "HS256"
access_token_expire_minutes: int = 30
# 网关配置
service_discovery_type: str = "consul" # consul, zookeeper, static
consul_host: str = "localhost"
consul_port: int = 8500
# 限流配置
rate_limit_enabled: bool = True
rate_limit_requests: int = 100 # 每分钟请求数
rate_limit_window: int = 60 # 时间窗口(秒)
# 熔断器配置
circuit_breaker_enabled: bool = True
circuit_breaker_failure_threshold: int = 5
circuit_breaker_recovery_timeout: int = 30
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
settings = Settings()
def get_settings() -> Settings:
"""获取配置实例"""
return settings
创建 .env 文件(不提交到版本控制):
env
# 开发环境配置
DEBUG=true
DATABASE_URL=postgresql://postgres:password@localhost:5432/api_gateway_dev
REDIS_URL=redis://localhost:6379/0
SECRET_KEY=dev-secret-key-change-in-production
2.3 数据库模型设计
API网关需要存储路由规则、服务信息、限流策略等。我们使用SQLAlchemy ORM定义数据模型:
创建 app/models.py:
# app/models.py
from sqlalchemy import Column, Integer, String, Boolean, DateTime, Text, ForeignKey
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from app.database import Base
class Service(Base):
"""微服务信息"""
__tablename__ = "services"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), unique=True, index=True, nullable=False)
description = Column(Text, nullable=True)
base_url = Column(String(500), nullable=False) # 服务基础URL
health_check_url = Column(String(500), nullable=True)
status = Column(String(20), default="healthy") # healthy, unhealthy, degraded
tags = Column(Text, nullable=True) # JSON格式的标签
# 负载均衡信息
load_balancer_type = Column(String(50), default="round_robin")
instances = relationship("ServiceInstance", back_populates="service", cascade="all, delete-orphan")
routes = relationship("Route", back_populates="service", cascade="all, delete-orphan")
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
class ServiceInstance(Base):
"""服务实例信息"""
__tablename__ = "service_instances"
id = Column(Integer, primary_key=True, index=True)
service_id = Column(Integer, ForeignKey("services.id", ondelete="CASCADE"))
instance_id = Column(String(100), unique=True, index=True)
host = Column(String(200), nullable=False)
port = Column(Integer, nullable=False)
weight = Column(Integer, default=1) # 权重
metadata = Column(Text, nullable=True) # JSON格式的元数据
status = Column(String(20), default="up") # up, down, draining
service = relationship("Service", back_populates="instances")
created_at = Column(DateTime(timezone=True), server_default=func.now())
last_heartbeat = Column(DateTime(timezone=True))
class Route(Base):
"""路由规则"""
__tablename__ = "routes"
id = Column(Integer, primary_key=True, index=True)
service_id = Column(Integer, ForeignKey("services.id", ondelete="CASCADE"))
path = Column(String(500), nullable=False, index=True)
methods = Column(String(200), default="GET,POST,PUT,DELETE") # 逗号分隔
strip_prefix = Column(Boolean, default=True) # 是否剥离路径前缀
timeout = Column(Integer, default=30) # 超时时间(秒)
retry_count = Column(Integer, default=3) # 重试次数
rate_limit_id = Column(Integer, ForeignKey("rate_limits.id"), nullable=True)
# 路由匹配优先级
priority = Column(Integer, default=0)
enabled = Column(Boolean, default=True)
service = relationship("Service", back_populates="routes")
rate_limit = relationship("RateLimit", back_populates="routes")
created_at = Column(DateTime(timezone=True), server_default=func.now())
class RateLimit(Base):
"""限流策略"""
__tablename__ = "rate_limits"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), unique=True, index=True)
limit = Column(Integer, nullable=False) # 请求数量
window = Column(Integer, nullable=False) # 时间窗口(秒)
algorithm = Column(String(50), default="fixed_window") # fixed_window, sliding_window
routes = relationship("Route", back_populates="rate_limit")
created_at = Column(DateTime(timezone=True), server_default=func.now())
class CircuitBreaker(Base):
"""熔断器状态"""
__tablename__ = "circuit_breakers"
id = Column(Integer, primary_key=True, index=True)
service_id = Column(Integer, ForeignKey("services.id", ondelete="CASCADE"))
failure_count = Column(Integer, default=0)
success_count = Column(Integer, default=0)
state = Column(String(20), default="closed") # closed, open, half_open
last_failure_time = Column(DateTime(timezone=True), nullable=True)
last_state_change = Column(DateTime(timezone=True))
service = relationship("Service")
2.4 数据库连接与迁移
创建 app/database.py:
# app/database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from app.config import settings
# 创建数据库引擎
engine = create_engine(
settings.database_url,
pool_pre_ping=True, # 连接池健康检查
pool_recycle=3600, # 连接回收时间(秒)
pool_size=20, # 连接池大小
max_overflow=40 # 最大溢出连接数
)
# 创建会话工厂
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 声明基类
Base = declarative_base()
def get_db():
"""获取数据库会话"""
db = SessionLocal()
try:
yield db
finally:
db.close()
创建数据库迁移脚本 alembic/env.py 和 alembic/versions/,这里我们使用Alembic进行数据库迁移。
2.5 应用入口与FastAPI实例
创建 app/main.py:
# app/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from app.config import settings
from app.database import engine, Base
from app.routers import gateway, admin
from app.middleware import (
AuthenticationMiddleware,
RateLimitMiddleware,
LoggingMiddleware,
CircuitBreakerMiddleware
)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时:创建数据库表
print("🚀 API网关启动中...")
Base.metadata.create_all(bind=engine)
# 初始化服务发现
from app.services.discovery import ServiceDiscovery
service_discovery = ServiceDiscovery()
await service_discovery.initialize()
# 启动健康检查
from app.services.health_check import HealthChecker
health_checker = HealthChecker()
health_checker.start()
print(f"✅ API网关已启动,访问地址: http://{settings.host}:{settings.port}")
print(f"📚 API文档: http://{settings.host}:{settings.port}/docs")
print(f"📊 管理后台: http://{settings.host}:{settings.port}/admin")
yield
# 关闭时:清理资源
print("🛑 API网关关闭中...")
health_checker.stop()
await service_discovery.close()
# 创建FastAPI应用
app = FastAPI(
title=settings.app_name,
version=settings.app_version,
description="企业级微服务API网关",
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
lifespan=lifespan
)
# 添加CORS中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 生产环境应限制来源
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 添加自定义中间件
app.add_middleware(AuthenticationMiddleware)
app.add_middleware(RateLimitMiddleware)
app.add_middleware(LoggingMiddleware)
app.add_middleware(CircuitBreakerMiddleware)
# 注册路由
app.include_router(gateway.router, prefix="", tags=["网关"])
app.include_router(admin.router, prefix="/admin", tags=["管理"])
@app.get("/health")
async def health_check():
"""健康检查接口"""
return {
"status": "healthy",
"service": settings.app_name,
"version": settings.app_version,
"timestamp": datetime.datetime.now().isoformat()
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app.main:app",
host=settings.host,
port=settings.port,
reload=settings.debug
)
至此,我们的基础框架已经搭建完成。下一部分我们将实现核心的路由转发功能。
第三部分:核心路由转发功能
3.1 路由匹配引擎
路由匹配是API网关的核心功能,需要高效地将请求路径映射到对应的后端服务。我们实现一个支持通配符和正则表达式的路由匹配器。
创建 app/services/router.py:
# app/services/router.py
import re
from typing import Dict, List, Optional, Tuple
from app.models import Route, Service
from app.database import SessionLocal
class RouteMatcher:
"""路由匹配引擎"""
def __init__(self):
self.routes: Dict[str, Route] = {}
self.path_patterns: List[Tuple[str, Route]] = []
self._load_routes()
def _load_routes(self):
"""从数据库加载路由规则"""
db = SessionLocal()
try:
routes = db.query(Route).filter(Route.enabled == True).all()
for route in routes:
self.routes[route.path] = route
# 将路径转换为正则表达式
pattern = self._path_to_regex(route.path)
self.path_patterns.append((pattern, route))
# 按优先级排序
self.path_patterns.sort(key=lambda x: x[1].priority, reverse=True)
print(f"✅ 加载了 {len(routes)} 条路由规则")
finally:
db.close()
def _path_to_regex(self, path: str) -> str:
"""将路径模式转换为正则表达式"""
# 替换路径参数
pattern = re.sub(r'{([^}]+)}', r'(?P<\1>[^/]+)', path)
# 处理通配符
pattern = pattern.replace('*', '.*')
# 确保精确匹配
pattern = f'^{pattern}$'
return pattern
def match(self, request_path: str, method: str) -> Optional[Tuple[Route, Dict]]:
"""匹配路由"""
# 先尝试精确匹配
if request_path in self.routes:
route = self.routes[request_path]
if self._check_method(route, method):
return route, {}
# 尝试模式匹配
for pattern, route in self.path_patterns:
match = re.match(pattern, request_path)
if match and self._check_method(route, method):
params = match.groupdict()
return route, params
return None
def _check_method(self, route: Route, method: str) -> bool:
"""检查请求方法是否允许"""
allowed_methods = [m.strip().upper() for m in route.methods.split(',')]
return method.upper() in allowed_methods or '*' in allowed_methods
def refresh(self):
"""刷新路由缓存"""
self.routes.clear()
self.path_patterns.clear()
self._load_routes()
# 全局路由匹配器实例
route_matcher = RouteMatcher()
3.2 服务发现与负载均衡
现代微服务架构中,服务实例是动态变化的。我们需要实现服务发现和负载均衡功能。
创建 app/services/discovery.py:
# app/services/discovery.py
import asyncio
import random
from typing import Dict, List, Optional
from app.models import Service, ServiceInstance
from app.database import SessionLocal
import httpx
import json
class LoadBalancer:
"""负载均衡器"""
def __init__(self):
self.strategies = {
'round_robin': self._round_robin,
'random': self._random,
'weighted': self._weighted,
'least_connections': self._least_connections
}
def select_instance(
self,
instances: List[ServiceInstance],
strategy: str = 'round_robin',
**kwargs
) -> Optional[ServiceInstance]:
"""选择服务实例"""
if not instances:
return None
# 过滤掉不健康的实例
healthy_instances = [inst for inst in instances if inst.status == 'up']
if not healthy_instances:
return None
# 选择负载均衡策略
selector = self.strategies.get(strategy, self._round_robin)
return selector(healthy_instances, **kwargs)
def _round_robin(self, instances: List[ServiceInstance], **kwargs) -> ServiceInstance:
"""轮询策略"""
if not hasattr(self, '_rr_counters'):
self._rr_counters = {}
instance_ids = [inst.id for inst in instances]
key = tuple(instance_ids)
if key not in self._rr_counters:
self._rr_counters[key] = 0
idx = self._rr_counters[key] % len(instances)
self._rr_counters[key] += 1
return instances[idx]
def _random(self, instances: List[ServiceInstance], **kwargs) -> ServiceInstance:
"""随机策略"""
return random.choice(instances)
def _weighted(self, instances: List[ServiceInstance], **kwargs) -> ServiceInstance:
"""加权随机策略"""
weights = [inst.weight for inst in instances]
total = sum(weights)
rand = random.uniform(0, total)
cumulative = 0
for inst, weight in zip(instances, weights):
cumulative += weight
if rand <= cumulative:
return inst
return instances[-1]
def _least_connections(self, instances: List[ServiceInstance], **kwargs) -> ServiceInstance:
"""最少连接策略(简化版)"""
# 实际项目中会从监控系统获取连接数
return instances[0]
class ServiceDiscovery:
"""服务发现"""
def __init__(self):
self.services: Dict[str, Service] = {}
self.instances: Dict[str, List[ServiceInstance]] = {}
self.load_balancer = LoadBalancer()
self._initialized = False
async def initialize(self):
"""初始化服务发现"""
if self._initialized:
return
# 从数据库加载服务信息
self._load_services()
# 根据配置选择服务发现方式
from app.config import settings
if settings.service_discovery_type == 'consul':
await self._init_consul()
elif settings.service_discovery_type == 'zookeeper':
await self._init_zookeeper()
else:
# 静态配置
self._init_static()
self._initialized = True
print(f"✅ 服务发现已初始化,发现 {len(self.services)} 个服务")
def _load_services(self):
"""从数据库加载服务"""
db = SessionLocal()
try:
services = db.query(Service).all()
for service in services:
self.services[service.name] = service
# 加载服务实例
instances = db.query(ServiceInstance).filter(
ServiceInstance.service_id == service.id,
ServiceInstance.status == 'up'
).all()
self.instances[service.name] = instances
finally:
db.close()
async def _init_consul(self):
"""初始化Consul客户端"""
from app.config import settings
import consul
# 创建Consul客户端
c = consul.Consul(
host=settings.consul_host,
port=settings.consul_port
)
# 获取所有服务
services = c.agent.services()
for service_id, service_info in services.items():
service_name = service_info.get('Service')
if service_name not in self.services:
# 动态添加服务
self._add_dynamic_service(service_name, service_info)
def _init_static(self):
"""静态服务发现"""
# 使用数据库中的配置
pass
def _add_dynamic_service(self, name: str, info: Dict):
"""添加动态发现的服务"""
# 简化实现
pass
def get_service(self, name: str) -> Optional[Service]:
"""获取服务信息"""
return self.services.get(name)
def get_service_instance(
self,
service_name: str,
strategy: str = 'round_robin'
) -> Optional[ServiceInstance]:
"""获取服务实例"""
instances = self.instances.get(service_name, [])
return self.load_balancer.select_instance(instances, strategy)
async def close(self):
"""关闭服务发现"""
self._initialized = False
# 全局服务发现实例
service_discovery = ServiceDiscovery()
3.3 HTTP客户端与代理转发
创建高效的HTTP客户端来处理请求转发。
创建 app/clients/http_client.py:
# app/clients/http_client.py
import httpx
from typing import Dict, Any, Optional
import json
import time
from app.config import settings
class GatewayHTTPClient:
"""网关HTTP客户端"""
def __init__(self):
# 创建连接池
limits = httpx.Limits(
max_connections=1000,
max_keepalive_connections=100
)
self.client = httpx.AsyncClient(
limits=limits,
timeout=httpx.Timeout(30.0),
follow_redirects=False
)
self.circuit_breakers: Dict[str, Dict] = {}
async def forward_request(
self,
method: str,
target_url: str,
headers: Dict[str, str],
body: Optional[bytes] = None,
params: Optional[Dict] = None,
timeout: int = 30
) -> httpx.Response:
"""转发请求"""
# 检查熔断器状态
if self._is_circuit_open(target_url):
raise CircuitBreakerOpen(f"Circuit breaker open for {target_url}")
try:
# 发送请求
start_time = time.time()
response = await self.client.request(
method=method,
url=target_url,
headers=headers,
content=body,
params=params,
timeout=timeout
)
elapsed = time.time() - start_time
# 更新熔断器状态
self._update_circuit_status(target_url, success=True)
# 记录日志
self._log_request(method, target_url, response.status_code, elapsed)
return response
except Exception as e:
# 更新熔断器状态
self._update_circuit_status(target_url, success=False)
# 重新抛出异常
raise
def _is_circuit_open(self, target_url: str) -> bool:
"""检查熔断器是否开启"""
# 简化实现
return False
def _update_circuit_status(self, target_url: str, success: bool):
"""更新熔断器状态"""
# 简化实现
pass
def _log_request(
self,
method: str,
url: str,
status_code: int,
elapsed: float
):
"""记录请求日志"""
# 简化实现
if settings.debug:
print(f"🌐 {method} {url} -> {status_code} ({elapsed:.3f}s)")
async def close(self):
"""关闭客户端"""
await self.client.aclose()
class CircuitBreakerOpen(Exception):
"""熔断器开启异常"""
pass
# 全局HTTP客户端实例
http_client = GatewayHTTPClient()
3.4 网关路由实现
现在将这些组件组合起来,实现完整的网关路由。
创建 app/routers/gateway.py:
# app/routers/gateway.py
from fastapi import APIRouter, Request, Response, HTTPException
from fastapi.responses import JSONResponse
from app.services.router import route_matcher
from app.services.discovery import service_discovery
from app.clients.http_client import http_client
import json
router = APIRouter()
@router.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
async def gateway_proxy(request: Request, path: str):
"""网关代理入口"""
# 构建完整请求路径
full_path = f"/{path}" if path else "/"
# 匹配路由
match_result = route_matcher.match(full_path, request.method)
if not match_result:
raise HTTPException(status_code=404, detail="Route not found")
route, path_params = match_result
# 获取服务信息
service = service_discovery.get_service(route.service.name)
if not service:
raise HTTPException(status_code=503, detail="Service unavailable")
# 选择服务实例
instance = service_discovery.get_service_instance(
service.name,
strategy=service.load_balancer_type
)
if not instance:
raise HTTPException(status_code=503, detail="No healthy instances")
# 构建目标URL
target_path = full_path
if route.strip_prefix:
# 移除路由前缀
target_path = full_path[len(route.path):] or "/"
target_url = f"http://{instance.host}:{instance.port}{target_path}"
# 准备请求头
headers = dict(request.headers)
# 移除Host头,避免干扰
headers.pop("host", None)
# 添加网关标识
headers["X-API-Gateway"] = "fastapi-gateway"
headers["X-Forwarded-For"] = request.client.host if request.client else "unknown"
# 获取请求体
body = await request.body()
try:
# 转发请求
response = await http_client.forward_request(
method=request.method,
target_url=target_url,
headers=headers,
body=body if body else None,
params=dict(request.query_params),
timeout=route.timeout
)
# 构建响应
content = response.content
if response.headers.get("content-length"):
content_length = int(response.headers["content-length"])
else:
content_length = len(content) if content else 0
# 创建FastAPI响应
fastapi_response = Response(
content=content,
status_code=response.status_code,
headers=dict(response.headers)
)
return fastapi_response
except Exception as e:
# 错误处理
error_detail = f"Gateway error: {str(e)}"
print(f"❌ 网关转发失败: {error_detail}")
return JSONResponse(
status_code=502,
content={
"error": "Bad Gateway",
"message": error_detail,
"service": service.name,
"path": full_path
}
)
@router.get("/gateway/routes")
async def list_routes():
"""列出所有路由"""
routes = []
for path, route in route_matcher.routes.items():
routes.append({
"path": path,
"service": route.service.name,
"methods": route.methods,
"enabled": route.enabled,
"priority": route.priority
})
return {"routes": routes}
@router.post("/gateway/refresh")
async def refresh_routes():
"""刷新路由缓存"""
route_matcher.refresh()
return {"message": "Routes refreshed successfully"}
至此,我们的核心路由转发功能已经完成。下一部分我们将实现认证授权、限流熔断等高级功能。