first version
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
# 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<String>) {
|
||||
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: <value>` 或 Query `token=<value>`
|
||||
|
||||
### 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<T>/AesQuery<T>/AesSignQuery<T>),T 需实现 ISerialization<T>
|
||||
let resp1 = client.signQuery<SimApiLoginItem>("/api/hello", body: "{\"a\":1}")
|
||||
let resp2 = client.aesQuery<SimApiLoginItem>("/api/data", body: "{\"a\":1}")
|
||||
let resp3 = client.aesSignQuery<SimApiLoginItem>("/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<SimApiCommonController>(),
|
||||
TypeInfo.of<SimApiAuthController>(),
|
||||
]))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 未实现模块(选项占位)
|
||||
|
||||
以下 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
|
||||
Reference in New Issue
Block a user