这是一个基于 axum (v0.8) 的、结构化的、生产级的 Rust Web 服务模板。它集成了 Nacos 作为服务发现和动态配置中心,并使用 SeaORM (v1.0) 作为数据库 ORM,以及 bb8-redis 作为 Redis 连接池。
本项目旨在提供一个高度模块化、可扩展且遵循 Rust 最佳实践的后端服务起点,其架构设计深受 Spring Boot 思想启发,但以 Rust 的方式(显式、安全、高性能)实现。
- Web 框架:
axum(v0.8) - 异步运行时:
tokio(v1) - 服务治理:
nacos-sdk(v0.5) - 用于服务发现和动态配置 - 数据库 (ORM):
sea-orm(v1.0) - 数据库 (Driver):
sqlx-mysql - Redis 客户端:
redis(v0.32) +bb8-redis(v0.24) (连接池) - HTTP 客户端:
reqwest(v0.12) - 用于服务间调用 - 序列化/反序列化:
serde(serde_yaml, serde_json) - 错误处理:
anyhow(用于main),thiserror(用于AppError) - 日志:
tracing(集成tower-http) - 异步 Trait:
async-trait(用于 Nacos 监听器) - 条件编译:
cfg-if(用于优雅停机) - 配置占位符:
shellexpand(已移除,采用 Nacos 直配)
- 清晰的分层 (SoC):
main.rs: 应用程序入口 (极其简洁,只负责调用)。router.rs: 封装所有 Axum 路由和顶层中间件的组装。setup/: 封装所有“一次性”的启动任务(如创建客户端、连接池、添加监听器)。state.rs: 定义全局共享状态 (AppState)。config/: 定义和加载配置结构。handlers/: HTTP 处理器 (Controllers),负责请求校验、DTO 转换和调用 Service。services/: 核心业务逻辑,不关心 HTTP。repository/: 数据库访问层,封装SeaORM查询。models/:SeaORM实体 (Entities) 定义。clients/: 封装对外部微服务(如auth-service)的 HTTP 调用 (类似 Feign)。response.rs: 统一的 API 响应结构ApiResponse<T>(类似 Java 的R<T>)。errors.rs: 统一的错误处理 (AppError+ServiceError+impl IntoResponse)。
- 服务发现: 启动时自动将服务注册到 Nacos。
- 动态配置: 启动时从 Nacos 加载配置,并实时监听配置变更,通过
RwLock动态更新AppState中的配置。 - 认证与授权:
middleware/auth.rs:- 实现了“自认证”中间件
mw_require_auth,通过clients/auth_client调用auth-service的/check_token接口,并提取CurrentUser放入请求extensions中。 - 提供了
check_permission辅助函数,用于在 Handler 内部检查CurrentUser的权限。
- 实现了“自认证”中间件
handlers/*.rs:- 受保护的 Handler (处理器) 负责在函数开头通过
Extension<Arc<CurrentUser>>获取用户。 - 并在函数体内部第一行调用
check_permission(&user, "...")?来实现类似@PreAuthorize的声明式权限检查。
- 受保护的 Handler (处理器) 负责在函数开头通过
- 优雅停机 (Graceful Shutdown):
- 同时监听
Ctrl+C(本地开发) 和SIGTERM(K8s/Docker)。 - 在服务停止前,主动向 Nacos 注销服务实例,防止流量黑洞。
- 同时监听
axum-template/
├── src/
│ ├── main.rs # 应用程序入口
│ ├── router.rs # 路由组装
│ ├── state.rs # AppState 定义
│ ├── errors.rs # AppError / ServiceError / IntoResponse
│ ├── response.rs # ApiResponse<T> 定义
│ │
│ ├── config/ # 配置
│ │ ├── mod.rs # 基础配置 (Config, 从 .env 加载)
│ │ └── app_specific.rs # 业务配置 (AppSpecificConfig, 从 Nacos 解析)
│ │
│ ├── setup/ # 启动逻辑封装
│ │ ├── mod.rs # 顶层 setup 函数 (setup_application_state, run_server)
│ │ ├── database.rs # build_db_pool
│ │ ├── http.rs # build_http_client
│ │ ├── nacos.rs # Nacos 客户端/注册/监听器
│ │ └── redis.rs # build_redis_pool
│ │
│ ├── clients/ # 微服务客户端 (类似 Feign)
│ │ ├── mod.rs # 声明
│ │ ├── service_client.rs # 通用 Nacos HTTP 客户端
│ │ └── auth_client.rs # Auth 服务客户端
│ │
│ ├── handlers/ # HTTP 处理器 (Controllers)
│ │ ├── mod.rs
│ │ ├── health_handler.rs
│ │ ├── hello_handler.rs
│ │ ├── kms_app_access_handler.rs
│ │ └── redis_handler.rs
│ │
│ ├── middleware/ # 中间件
│ │ ├── mod.rs
│ │ ├── auth.rs # 认证 (mw_require_auth, CurrentUser) 和授权 (check_permission)
│ │ └── logging.rs
│ │
│ ├── models/ # 数据库实体 (SeaORM)
│ │ ├── mod.rs
│ │ └── kms_app_access.rs
│ │
│ ├── repository/ # 数据库访问 (SeaORM)
│ │ ├── mod.rs
│ │ └── kms_app_access_repo.rs
│ │
│ └── services/ # 业务逻辑
│ ├── mod.rs
│ └── kms_app_access_service.rs
│
├── tests/ # 集成测试
│ └── health_check.rs
│
├── .env # 本地开发环境变量
├── Cargo.toml # 依赖管理 (pom.xml)
├── Dockerfile # 多阶段、可重用的 Dockerfile
├── .dockerignore # Docker 忽略文件
├── .gitignore # Git 忽略文件
└── README.md # 本文档
本模板被设计为可以无缝(或通过最小改动)融入现有的 Spring Cloud + Nacos 体系。
Spring Boot 服务可以通过 Nacos 和 OpenFeign 像调用其他 Java 服务一样调用本服务。
-
Rust 服务注册: 本模板 (
axum-template) 启动时会以APP_NAME(来自.env,例如axum-template-service) 注册到 Nacos。 -
Java Feign 客户端: 在你的 Spring Boot 项目中,定义一个 Feign 客户端:
// 1. `value` 必须匹配 Rust 服务的 APP_NAME @FeignClient(value = "axum-template-service") public interface RemoteRustService { // 2. 路由和响应体必须匹配 Rust 端的定义 // 对应 /hello 路由 @GetMapping("/hello") ApiResponse<HelloResponseDto> getHelloConfig(); // 对应 /app-access/{id} 路由 @GetMapping("/app-access/{id}") ApiResponse<KmsAppAccessResponseDto> getAppAccessById(@PathVariable("id") Long id); // (注意:你需要在 Java 端定义 ApiResponse<T>, HelloResponseDto, KmsAppAccessResponseDto) // (它们必须与 Rust 的 `response.rs` 和 `handlers/` 里的 DTO 结构一致) }
本模板通过 src/clients/ 模块实现了“Rust 版的 Feign”,它封装了服务发现和 HTTP 调用。
- Java 服务注册: 你的 Java 服务(例如
upms-service)正常注册到 Nacos。 - Rust 客户端封装:
src/clients/service_client.rs: 提供了通用的get_service和post_service函数。它们封装了 Nacos 服务发现 (select_one_healthy_instance) 和reqwestHTTP 调用。src/clients/auth_client.rs: 提供了特定业务的客户端。它负责:- 从
Config中获取服务名 (e.g.,AUTH_SERVICE_NAME)。 - 准备请求参数 (
query_params)。 - 调用
service_client::get_service_with_group(...)。 - 将返回的 JSON 响应解析为 Rust
struct。
- 从
- 调用:
src/middleware/auth.rs(认证中间件)通过State<AppState>获取共享状态,然后调用auth_client::check_token(&state, ...)来执行服务间调用。
-
准备环境: Nacos, MySQL, Redis,
auth-service(Java) 正在运行。 -
准备数据库: 在 MySQL 中创建库和
kms_app_access表。 -
配置 Nacos: 在非 public 命名空间下,创建
axum-template.yaml配置(见上方 YAML 示例)。 -
配置本地
.env:- 复制
README.md中的.env示例,创建.env文件。 - 必须修改
NACOS_NAMING_NAMESPACE,NACOS_CONFIG_NAMESPACE,NACOS_ADDR。 - 必须修改 Nacos 中
database.url的用户名/密码。
- 复制
-
运行:
cargo run -
测试:
curl http://localhost:4000/(健康检查)curl -H "Authorization: Bearer <token>" http://localhost:4000/hellocurl -H "Authorization: Bearer <token>" http://localhost:4000/app-access/1
-
构建生产镜像:
docker build --build-arg APP_NAME=axum-template -t my-axum-app . # 运行时 *必须* 通过 -e 传入所有 .env 变量 docker run -p 4000:4000 -e APP_NAME="axum-template" -e SERVER_ADDR="0.0.0.0:4000" -e NACOS_ADDR="..." ... my-axum-app