# SimApi for Cangjie(simapi) > 仓颉版 SimApi:ASP.NET Core 风格 API 基础框架,移植自 C# 项目 [SimApi](https://github.com/SimcuTeam/simapi-net)(`E:\simcu\simapi-net`)。 提供**统一响应格式、异常拦截、Token 认证、缓存、工具集、HTTP 客户端**等 API 基础能力。 --- ## 快速开始 ```cangjie package your_app import soulsoft_web_http.* import soulsoft_web_routing.* import soulsoft_web_hosting.* import soulsoft_extensions_logging.* import soulsoft_extensions_injection.* import simapi.extensions.* import simapi.communications.* main(args: Array) { let builder = WebHost.createBuilder(args) builder.services.addRouting() builder.services.addLogging() // 注册 SimApi 服务(与 addLogging 同样式) builder.addSimApi { options => options.enableSimApiAuth = true // Token 认证(未配 Redis 自动用 InMemory) options.enableSimApiCache = true // 缓存 options.enableSimApiException = true // 全局异常拦截 } let host = builder.build() host.useSimApi() // 业务接口:返回统一响应格式 host.mapGet("hello") { context => context.response.write(SimApiBaseResponse().toJsonString(dataJson: "\"hello cangjie.\"")) } host.run() } ``` ### 统一响应格式 所有接口输出 JSON,HTTP 状态码始终 `200`,错误信息在 `code` 字段: | code | 含义 | | ---- | ---------- | | 200 | 成功 | | 204 | 无数据 | | 400 | 参数错误 | | 401 | 需要登录 | | 403 | 无权访问 | | 404 | 资源不存在 | | 500 | 服务器错误 | ### 异常处理流程 ``` 请求 → SimApiExceptionMiddleware(全异常捕获→HTTP 200+JSON) → SimApiAuthMiddleware(Token→LoginInfo) → 路由 → 业务处理 ``` --- ## 项目结构 ``` simapi-cj/ ├── cjpm.toml # 包配置 ├── src/ │ ├── communications/ # SimApiBaseResponse, PageResponse, SimApiLoginItem, ApiResult, 请求 DTO │ ├── configurations/ # SimApiOptions + 各模块 Option(含 ConfigureSimApiXxx 回调) │ ├── controllers/ # SimApiBaseController, SimApiCommonController, SimApiAuthController(MVC 写法) │ ├── exceptions/ # SimApiException │ ├── extensions/ # SimApiExtensions(addSimApi / useSimApi + 内置路由) │ ├── helpers/ # SimApiError, SimApiUtil, SimApiAuth, SimApiCache, SimApiHttpClient │ ├── interfaces/ # ISimApiAuthChecker │ ├── logger/ # SimApiLogger, SimApiLoggerProvider(彩色日志) │ └── middlewares/ # SimApiExceptionMiddleware, SimApiAuthMiddleware, SimApiRequestLogMiddleware ``` --- ## 模块说明 ### 1. 错误处理 — SimApiError ```cangjie import simapi.helpers.* SimApiError.error(500, "服务器内部错误") // 直接抛错 SimApiError.errorWhen(amount <= 0, 400, "金额无效") // 条件为 true 时抛错 SimApiError.errorWhenFalse(hasPermission, 403, "无权操作") SimApiError.errorWhenNone(someOptional, 404, "用户不存在") ``` ### 2. 认证 — SimApiAuth ```cangjie import simapi.helpers.* import simapi.communications.* let auth = SimApiAuth(redisConfiguration: "") // 配 Redis 用 Redis,否则 InMemory let token = auth.login(SimApiLoginItem(id: "user-001")) // 默认 7 天 let login = auth.getLogin(token) // 获取登录信息 auth.logout(token) // 退出登录 auth.logoutAll("user-001") // 退出全部 ``` - **Redis 模式**:配置 `RedisConfiguration`(如 `"localhost:6379"`)时使用,支持多实例共享 - **InMemory 模式**:零配置,适合开发/测试;重启后登录态丢失 - **Token 传参**:Header `Token: ` 或 Query `token=` ### 3. 缓存 — SimApiCache ```cangjie let cache = SimApiCache(redisConfiguration: "") cache.set("key", "value") let v = cache.get("key") // ?String cache.hasKey("key") // Bool cache.remove("key") ``` Key 自动加前缀 `SimApi:Cache:`。 ### 4. 工具集 — SimApiUtil ```cangjie SimApiUtil.cstNow // UTC+8 时间 SimApiUtil.timestampNow // 秒级时间戳 SimApiUtil.md5("text") // 32 位十六进制 SimApiUtil.sha1("text") // 40 位 SimApiUtil.base64Encode("text") / base64Decode("...") SimApiUtil.checkCell("13800138000") // 手机号 SimApiUtil.checkEmail("a@b.com") // 邮箱 ``` ### 5. HTTP 客户端 — SimApiHttpClient 用于调用其他带签名/AES 的 SimApi 服务: ```cangjie let client = SimApiHttpClient(options: SimApiHttpClientOptions()) // 配置 server/appId/appKey // 返回泛型 T(对齐 .NET SignQuery/AesQuery/AesSignQuery),T 需实现 ISerialization let resp1 = client.signQuery("/api/hello", body: "{\"a\":1}") let resp2 = client.aesQuery("/api/data", body: "{\"a\":1}") let resp3 = client.aesSignQuery("/api/data", body: "{\"a\":1}") ``` ### 5.1 请求日志 — enableRequestLog 记录每次请求的方法、URL、请求头、请求体、响应状态码与耗时: ```cangjie builder.addSimApi { options => options.enableRequestLog = true options.simApiRequestLogOptions.showFullHeader = true // 打印完整 Header(默认只打 Token/Query-Id) options.simApiRequestLogOptions.requestStringLogLength = 200 // 请求体截断长度(0 不截断) } ``` 输出示例: ``` [GET] /hello *( RequestHeaders [Full] ) => {"host":"127.0.0.1:5000",...} *( RequestBody ) => *( Response [200] ) => 1.756400ms ``` ### 5.2 日志格式 — SimApiLogger `enableLogger`(默认 `true`)时自动使用 `SimApiLoggerProvider`(替换 soulsoft 默认控制台格式),输出格式对齐 C# 原版: ``` [ 分类 ][ 时间:毫秒 ][ 级别 ] 消息内容 ``` 按级别着色: | 级别 | 颜色 | |------|------| | Debug | 深紫(DarkMagenta) | | Info | 深青(DarkCyan) | | Warn | 黄(Yellow) | | Error | 红(Red) | | Fatal | 深红(DarkRed 粗体近似) | | 其他 | 白(White) | ### 6. 内置路由(UseSimApi 自动注册) | 路由 | 方法 | 条件 | 说明 | | ----------------- | -------- | ---------------------------- | -------------------------- | | `/versions` | GET/POST | 始终 | 返回 SimApi/App 版本 | | `/user/info` | POST | `enableSimApiAuth` | 需登录,返回 LoginInfo | | `/auth/logout` | POST | `enableSimApiAuth` | 退出登录 | | `/exception/{code}` | GET | 始终 | 错误反馈 | ### 7. 认证后处理 Hook — ISimApiAuthChecker ```cangjie import simapi.interfaces.* class MyAuthChecker <: ISimApiAuthChecker { public func run(loginItem: SimApiLoginItem, token: String): Unit { // 认证成功后执行 } } ``` --- ## SimApiOptions 完整配置 ```cangjie builder.addSimApi { options => options.redisConfiguration = "localhost:6379" // Redis(可选) // 功能开关 options.enableSimApiAuth = false // Token 认证 options.enableSimApiCache = true // 缓存 options.enableSimApiException = true // 全局异常拦截 options.enableSimApiResponseFilter = true // 响应统一封装 options.enableSimApiHttpClient = false // HTTP 客户端 options.enableRequestLog = false // 请求日志中间件 options.enableCors = true // 全量 CORS options.enableLogger = true // 控制台日志 // .NET 风格子模块配置回调(对齐 C# ConfigureSimApiXxx) options.configureSimApiRoute { route => route.userInfoRoute = Some("user/info") route.logoutRoute = Some("auth/logout") } options.configureSimApiRequestLog { opt => opt.showFullResponse = true opt.showFullHeader = false opt.requestStringLogLength = 50 } options.configureSimApiHttpClient { http => http.appId = "your-app-id" http.appKey = "your-app-key" http.server = "https://api.example.com" } } ``` ## 内置控制器(MVC 写法) simapi 提供 Spire MVC 控制器(继承 `SimApiBaseController`),宿主通过 `addControllers` + 手动 `AssemblyPart` 注册(当前 cjc 无法自动扫描包子包): | 控制器 | 路由 | 说明 | |--------|------|------| | `SimApiCommonController` | `/exception/{code}`、`/webconfig`、`/user/info` | 通用内置路由 | | `SimApiAuthController` | `/auth/logout` | 退出登录 | | `SimApiBaseController` | — | 基类:`loginInfo` / `loginToken` / `requireLogin()` | ```cangjie import simapi.controllers.* // 控制器写法:继承 SimApiBaseController,注解路由 + DI 注入 public class MyController <: SimApiBaseController { private let _auth: SimApiAuth public init(auth: SimApiAuth) { this._auth = auth } @HttpPost["my/route"] public func myAction(@FromBody request: MyRequest): ApiResult { requireLogin() ApiResult.ok() } } // 宿主注册 let mvc = builder.services.addControllers() mvc.addApplicationPart(AssemblyPart("simapi.controllers", [ TypeInfo.of(), TypeInfo.of(), ])) ``` --- ## 未实现模块(选项占位) 以下 C# 原包功能因仓颉生态暂无对应库,**选项保留但未实现**: | 选项 | 原功能 | 状态 | |------|--------|------| | `enableSimApiDoc` | Swagger 文档 | ❌ 未实现 | | `enableSimApiStorage` | S3/MinIO 存储 | ❌ 未实现 | | `enableSynapse` | MQTT 通信 | ❌ 未实现 | | `enableJob` | Hangfire 任务调度 | ❌ 未实现 | | `enableSimApiAuthGate` | Auth Center 网关鉴权 | ❌ 未实现 | | `SimApiAesUtil` | AES-256-CBC | ⚠️ 仓颉 std 无 AES,暂用 Base64 占位 | --- ## 依赖 | 依赖 | 用途 | |------|------| | `soulsoft_web_http / routing / hosting` | Web 框架(ASP.NET Core 仓颉移植版) | | `soulsoft_extensions_logging` 系列 | 日志 | | `soulsoft_extensions_injection` | 依赖注入 | | `soulsoft_extensions_configuration` | 配置 | | `soulsoft_serialization` | JSON 序列化 | | `redis`(pkg.cangjie-lang.cn) | Redis 客户端(认证/缓存 Redis 模式) | | `stdx`(CANGJIE_STDX_PATH) | 标准扩展库(md5/sha1/base64/http) | > 构建前需设置 `CANGJIE_STDX_PATH` 指向本地 stdx 的 `static/stdx` 目录。 --- ## 许可证 MIT