Skip to content

运维端点

ACE 内置一组运维端点(Actuator),无需额外依赖,通过 opsMiddleware 挂载即可获得 Bean 注册表、配置快照、路由映射和日志级别等诊断能力。所有端点返回 JSON,便于与监控平台集成。

快速启用

在应用入口将 opsMiddleware 注册到路由器:

cangjie
import ace_framework.*
import ace_framework_runtime.*
import ace_router.*

let router = Router()
opsMiddleware(router)          // 挂载所有 /ace/* 端点

router.get("/api/hello") { ctx, _ -> ctx.body("hello") }

let app = App()
app.use(router.routes())
listen(app, "0.0.0.0", 8080)

也可挂载到子路由,限定访问前缀:

cangjie
let internalRouter = Router("/internal")
opsMiddleware(internalRouter)  // 端点变为 /internal/ace/*

端点说明

GET /ace/beans

返回当前容器中所有已注册 Bean 的列表,包含 Bean 名称、类型、作用域及是否为 Primary。

bash
curl http://localhost:8080/ace/beans
json
{
  "beans": [
    { "name": "userService",    "type": "UserService",    "scope": "singleton", "primary": true },
    { "name": "orderService",   "type": "OrderService",   "scope": "singleton", "primary": false },
    { "name": "requestScoped1", "type": "AuthContext",    "scope": "request",   "primary": false }
  ],
  "total": 3
}

GET /ace/env

返回当前合并后的完整配置快照。敏感字段自动打码:字段名含 secretpasswordtokenkey 的值替换为 "****"

bash
curl http://localhost:8080/ace/env
json
{
  "server.port": "8080",
  "server.host": "0.0.0.0",
  "database.url": "jdbc:sqlite:./data.db",
  "database.password": "****",
  "jwt.secret": "****",
  "app.name": "my-service"
}

打码规则

字段名(不区分大小写)包含以下任意关键字时,值替换为 "****"secret / password / token / key

示例:api_keyjwtSecretdb.passwordauthToken 均会被打码。

GET /ace/mappings

返回所有已注册的路由映射,包含 HTTP 方法、路径模式、处理函数名称和所属 Controller。

bash
curl http://localhost:8080/ace/mappings
json
{
  "mappings": [
    { "method": "GET",  "pattern": "/api/users",      "handler": "UserController.list",   "middlewares": ["authMiddleware"] },
    { "method": "POST", "pattern": "/api/users",      "handler": "UserController.create", "middlewares": ["authMiddleware"] },
    { "method": "GET",  "pattern": "/api/users/{id}", "handler": "UserController.getOne", "middlewares": [] }
  ],
  "total": 3
}

GET /ace/loggers

返回当前所有日志记录器的名称与级别,支持运行时动态调整(通过 POST 写回)。

bash
curl http://localhost:8080/ace/loggers
json
{
  "loggers": [
    { "name": "root",          "level": "INFO" },
    { "name": "ace.router",    "level": "DEBUG" },
    { "name": "ace.framework", "level": "INFO" },
    { "name": "app.service",   "level": "WARN" }
  ]
}

动态调整日志级别(POST,无需重启):

bash
curl -X POST http://localhost:8080/ace/loggers \
     -H "Content-Type: application/json" \
     -d '{"name": "ace.router", "level": "DEBUG"}'

安全建议

运维端点暴露了敏感的内部状态,生产环境必须做访问控制。推荐方案:

方案一:@Profile 限制

cangjie
@Profile["dev"]
@Service
class OpsSetup {
    @PostConstruct
    func setup(): Unit {
        opsMiddleware(globalRouter)
    }
}

方案二:路由 IP 白名单中间件

cangjie
let opsRouter = Router("/ace")
opsRouter.use { ctx, next ->
    let ip = ctx.header("X-Real-IP") ?? ctx.remoteAddr()
    if (!ip.startsWith("10.") && !ip.startsWith("127.")) {
        ctx.status(403)
        ctx.body("""{"error":"forbidden"}""")
        return
    }
    await next()
}
opsMiddleware(opsRouter)

方案三:独立端口

cangjie
// 主服务:8080
listen(app, "0.0.0.0", 8080)

// 运维服务:仅监听本机,8081
let opsApp = App()
opsApp.use(opsRouter.routes())
listen(opsApp, "127.0.0.1", 8081)

生产环境必须保护运维端点

/ace/env 即便对敏感字段打码,仍可能暴露数据库地址、内部服务 URL 等信息。务必通过 IP 白名单、认证中间件或独立内网端口保护所有 /ace/* 路径。

基于 Apache-2.0 许可证发布