Appearance
天幕运行面 SDK 使用文档
本文说明如何在用户业务后端(Node.js / Java)中接入天幕动态 API与自定义 API。SDK 位于 rely-ons,封装换 Token、鉴权头与常用 HTTP 调用,避免每个项目重复写 fetch / HttpClient。
| 包 | 路径 | 适用 |
|---|---|---|
yc-runtime-sdk(npm) | rely-ons/yc-runtime-sdk | Node.js ≥ 18(ESM) |
yc-runtime-sdk | rely-ons/yc-runtime-sdk-java | Java 11+ |
| 文档 | 说明 |
|---|---|
| §4 参数获取来源 | 每个参数从哪里拿(平台菜单 / 业务系统 / 自建) |
| CHANGELOG.md | 版本变更记录 |
| §12 联调 FAQ | JSON 列、published_at、天幕调用失败、业务 404 |
1. 调用链路(推荐)
用户浏览器 → 您的业务后端(BFF)→ 天幕平台运行面 API
↑
只在这里配置 YC_ACCESS_KEY
不要把密钥放进前端 / 小程序- 动态 API:按数据模型发布,每个操作有独立路径(默认后缀
/list、/get、/create、/update、/delete),HTTP 方法可在发布配置中调整。
基础段:{YC_BASE_URL}/dynamic-api/v1/{projectId}/{modelKey}
例:http://localhost:8081/yc/dynamic-api/v1/xxx/products/list(分页列表,默认 POST) - 自定义 API:按 apiKey 发布,路径形如
{YC_BASE_URL}/custom-api/v1/{projectId}/{apiKey}
SDK 在启用鉴权时自动完成:
POST .../_auth/token,请求头X-Access-Key: <接入密钥>- 拿到
accessToken后,业务请求带Authorization: Bearer <token> - Token 在内存中缓存,临近过期前自动刷新
2. 平台侧准备(首次接入)
在 sky-curtain 管理端完成(与是否使用 SDK 无关):
| 步骤 | 菜单位置 | 说明 |
|---|---|---|
| 数据源 | 服务器管理 → 连接配置 | 指向业务 MySQL 等 |
| 动态 API | 服务器管理 → 数据模型 | 对表发布 list/get/create/put/delete |
| 自定义 API | 服务器管理 → 自定义 API | 编排并发布 |
| 运行凭证 | 服务器管理 → 服务配置 | 开启鉴权,生成接入密钥(ycdk_...) |
各参数具体从哪里复制、填写,见 §4 配置参数与获取来源。
更细的逐步操作可参考:
3. 安装
SDK 支持公开发布(标准明文包,无加密):npm 包名 yc-runtime-sdk,Maven 坐标 team.dream.yc:yc-runtime-sdk。
3.0 前置要求
| 项 | Node.js | Java |
|---|---|---|
| 运行环境 | Node ≥ 18 | JDK ≥ 11 |
| 模块格式 | 建议 package.json 中 "type": "module" | — |
| 获取 SDK | npm install yc-runtime-sdk 或克隆本仓库 file: 安装 | Maven Central 或 mvn install |
| 业务项目 | 用户自己的 BFF / 后端(非 sky-curtain 前端) | 同上 |
3.0.1 从公共仓库安装(推荐,发布后)
Node.js
bash
npm install yc-runtime-sdkjavascript
import { createClientFromEnv } from 'yc-runtime-sdk';Java(Maven Central 同步后即可,无需额外 repository)
xml
<dependency>
<groupId>team.dream.yc</groupId>
<artifactId>yc-runtime-sdk</artifactId>
<version>1.0.0</version>
</dependency>java
import team.dream.yc.runtime.YcRuntimeClient;
YcRuntimeClient yc = YcRuntimeClient.fromEnv();3.0.2 从本仓库本地安装(未发布或开发联调)
若尚未执行公开发布,或需修改 SDK 源码联调,请继续阅读下文 3.1 / 3.2。
3.1 Node.js(yc-runtime-sdk)
步骤 1:进入业务后端目录
例如演示工程:
bash
cd test-projects/example-1/backend或您自建的 my-company-api 等项目根目录(该目录下有 package.json)。
步骤 2:按相对路径安装
file: 后面是天幕仓库里 rely-ons/yc-runtime-sdk 相对于当前业务项目的路径,请按实际目录调整:
| 业务项目位置示例 | 推荐命令 |
|---|---|
test-projects/example-1/backend | npm install file:../../../rely-ons/yc-runtime-sdk |
与 rely-ons 同级的 my-backend/ | npm install file:../rely-ons/yc-runtime-sdk |
| 业务项目在仓库外、SDK 在固定目录 | npm install file:/绝对路径/天幕低代码/rely-ons/yc-runtime-sdk |
bash
# 在业务后端根目录执行(示例:example-1)
npm install file:../../../rely-ons/yc-runtime-sdk使用 pnpm / yarn 时:
bash
pnpm add file:../../../rely-ons/yc-runtime-sdk
# 或
yarn add file:../../../rely-ons/yc-runtime-sdk步骤 3:确认 package.json
安装成功后应出现依赖项:
json
{
"type": "module",
"dependencies": {
"yc-runtime-sdk": "file:../../../rely-ons/yc-runtime-sdk"
}
}步骤 4:可选 — RSA 私钥模式
平台「服务配置」为 CLIENT_RSA 时,需额外安装:
bash
npm install jsonwebtoken步骤 5:验证能否引用
新建或运行一段脚本(如 scripts/check-sdk.mjs):
javascript
import { createClient } from 'yc-runtime-sdk';
const yc = createClient({
baseUrl: 'http://localhost:8081/yc',
projectId: 'test',
skipAuth: true,
});
console.log('SDK 加载成功', typeof yc.dynamic.list === 'function');bash
node scripts/check-sdk.mjs
# 输出 SDK 加载成功 true 即表示安装正确步骤 6:配置环境变量后正式使用
见 §4 配置参数与获取来源;代码入口:
javascript
import { createClientFromEnv } from 'yc-runtime-sdk';
const yc = createClientFromEnv();3.2 Java(team.dream.yc:yc-runtime-sdk)
步骤 1:将 SDK 安装到本机 Maven 仓库
在天幕低代码仓库根目录或任意能访问 rely-ons/yc-runtime-sdk-java 的路径执行:
bash
cd rely-ons/yc-runtime-sdk-java
mvn install -DskipTests成功结束时日志含 BUILD SUCCESS,本地仓库会有:
text
team.dream.yc : yc-runtime-sdk : 1.0.0步骤 2:业务项目添加依赖
在业务后端 pom.xml 的 <dependencies> 中增加:
xml
<dependency>
<groupId>team.dream.yc</groupId>
<artifactId>yc-runtime-sdk</artifactId>
<version>1.0.0</version>
</dependency>若业务工程与 SDK 在同一多模块父工程下,也可改为模块依赖(需自行在父 pom.xml 中 install 或 module 引用),一般用户项目独立时用上方的 mvn install 即可。
步骤 3:刷新 IDE / 编译
bash
cd 您的业务Java项目目录
mvn compileIDEA / Eclipse 执行 Maven Reload。
步骤 4:验证能否引用
java
import team.dream.yc.runtime.YcRuntimeClient;
import team.dream.yc.runtime.YcRuntimeConfig;
public class SdkSmoke {
public static void main(String[] args) {
YcRuntimeClient yc = new YcRuntimeClient(
YcRuntimeConfig.builder()
.baseUrl("http://localhost:8081/yc")
.projectId("test")
.skipAuth(true)
.build()
);
System.out.println("SDK 加载成功: " + (yc != null));
}
}编译运行无 ClassNotFoundException 即安装正确。
步骤 5:配置环境变量后正式使用
java
YcRuntimeClient yc = YcRuntimeClient.fromEnv();或显式构造:
java
YcRuntimeClient yc = YcRuntimeClient.create(
"http://localhost:8081/yc",
"你的项目ID",
"ycdk_你的接入密钥"
);3.3 安装后必配项(两种语言相同)
完成安装后,在业务后端配置(.env、系统环境变量或 K8s Secret):
bash
YC_BASE_URL=http://localhost:8081/yc
YC_PROJECT_ID=你的项目ID
YC_ACCESS_KEY=ycdk_平台服务配置中生成的密钥仅本地、且平台未配密钥试调时可临时:
bash
YC_INVOKE_SKIP_AUTH=13.4 从演示工程迁移(可选)
仓库 test-projects/example-1/backend 内原有 yc-client.js、yc-dynamic-client.js 与 SDK 逻辑等价。迁移步骤:
- 按 3.1 安装
yc-runtime-sdk(或npm install yc-runtime-sdk) - 保留现有
.env变量名(YC_BASE_URL、YC_PROJECT_ID、YC_ACCESS_KEY) - 将
import ... from './yc-dynamic-client.js'改为import { createClientFromEnv } from 'yc-runtime-sdk' - 用
yc.dynamic.*/yc.custom.invoke替换手写fetch
3.5 常见问题(安装)
| 问题 | 处理 |
|---|---|
npm install file:... 报路径找不到 | 检查相对路径是否从业务项目根指向 rely-ons/yc-runtime-sdk |
Cannot find package 'yc-runtime-sdk' | 未执行 npm install yc-runtime-sdk 或本地 file: 路径错误 |
Java Could not find artifact yc-runtime-sdk | 未对 rely-ons/yc-runtime-sdk-java 执行 mvn install |
| 修改 SDK 源码后业务未生效 | Node:在业务目录重新 npm install;Java:对 SDK 再 mvn install 后业务 mvn compile |
4. 配置参数与获取来源(必读)
本节说明 SDK 涉及的每一个参数:名称、用途、从哪里获取、填在什么位置。
获取来源分三类:
| 类型 | 含义 | 示例 |
|---|---|---|
| 平台 | 在天幕 sky-curtain / yc_user_service 上查看或生成 | YC_PROJECT_ID、YC_ACCESS_KEY、modelKey |
| 业务 | 您自己的用户系统、数据库、登录逻辑产生 | userJwt、id、自定义 body 字段 |
| 开发 | 本地联调时自行约定,非平台下发 | YC_INVOKE_SKIP_AUTH、currentPage |
4.1 SDK 连接参数(环境变量 / createClient)
在业务后端 .env、K8s Secret 或 createClient({ ... }) 中配置。
| 参数 | 必填 | 用途 | 获取来源(从哪里拿) | 填写位置 |
|---|---|---|---|---|
YC_BASE_URL | 是 | 天幕后端 API 根地址(含 /yc) | 运维 / 部署文档:本地一般为 yc_user_service 启动地址 + 上下文路径。例:application.properties 中 server.port=8081 且接口前缀为 /yc → http://localhost:8081/yc。生产为平台对外域名,如 https://api.your-company.com/yc。不是 sky-curtain 前端 Vite 地址(如 localhost:3000)。 | .env 或 createClient.baseUrl |
YC_PROJECT_ID | 是 | 标识要调用哪一个天幕应用(项目) | sky-curtain 管理端:进入目标应用后,浏览器地址栏 .../project/{项目ID}/... 中这一段(32 位左右字符串)。或 服务器管理 → API 管理 / 服务配置 / 数据模型 任一页面,当前应用即该项目。与「团队 ID」不同。 | .env 或 createClient.projectId |
YC_ACCESS_KEY | 生产建议 | 长期接入密钥,用于向平台换短期 Token | sky-curtain → 服务器管理 → 服务配置:校验方式选「接入密钥(换 Token)」/ PLATFORM_INVOKE 后,点击 「生成接入密钥」;弹窗中 ycdk_ 开头字符串仅展示一次,复制到后端环境变量。不是控制台登录 Token,不是 ycak_ 占位符。 | .env 或 createClient.accessKey |
YC_PLATFORM_ACCESS_KEY | 否 | 同上 | 与 YC_ACCESS_KEY 完全等价(SDK 兼容旧名)。来源同上。 | 二选一即可 |
YC_INVOKE_SKIP_AUTH | 否 | 跳过运行面鉴权(试调) | 开发自建:仅在本地联调、且平台未配有效密钥时设为 1。对应平台管理端「试调」时带的跳过头;生产必须关闭。 | .env 或 createClient.skipAuth: true |
YC_USER_JWT | 否 | 默认业务 JWT(动态 API) | 业务系统:用户登录后,由您的后端用与平台一致的密钥签发的 JWT(见下表 userJwt)。example-1 中即 auth.js 的 signToken 结果,密钥来自 .env 的 JWT_SECRET。 | .env 或 createClient.userJwt |
YC_CLIENT_RSA_PRIVATE_KEY | 否 | RSA 私钥 PEM(动态 API) | sky-curtain → 服务器管理 → 服务配置:校验方式选 「RSA 私钥签 JWT」/ CLIENT_RSA,点击 「生成 RSA 密钥对」;私钥仅展示一次,整段 PEM 存入环境变量(可多行或 \n)。公钥已写入平台项目配置。 | .env 或 createClient.rsaPrivateKeyPem |
YC_CLIENT_RSA_TTL_SECONDS | 否 | 自签 JWT 有效期(秒) | 开发自建,默认 600。与平台 Token TTL 无关。 | .env |
YC_DYNAMIC_INVOKE_SKIP_AUTH | 否 | 同 YC_INVOKE_SKIP_AUTH(example-1 兼容名) | 开发自建,与上相同。 | example-1 .env |
YC_DYNAMIC_REQUIRE_AUTH | 否 | 业务侧是否要求带凭证调动态 API | 开发自建:example-1 设为 1 表示必须鉴权;设为 0 且配合 skip 可本地放开。与平台「启用运行时鉴权」开关应一致。 | example-1 .env |
Node createClient / Java YcRuntimeConfig 字段与环境变量一一对应:
| 代码字段 | 环境变量 |
|---|---|
baseUrl | YC_BASE_URL |
projectId | YC_PROJECT_ID |
accessKey | YC_ACCESS_KEY / YC_PLATFORM_ACCESS_KEY |
skipAuth | YC_INVOKE_SKIP_AUTH=1 |
userJwt | YC_USER_JWT |
rsaPrivateKeyPem | YC_CLIENT_RSA_PRIVATE_KEY |
rsaTtlSeconds | YC_CLIENT_RSA_TTL_SECONDS |
本地最简 .env 示例:
env
YC_BASE_URL=http://localhost:8081/yc
YC_PROJECT_ID=cfeb9dd64869922937499a5e453e6f34
YC_ACCESS_KEY=ycdk_从服务配置「生成接入密钥」复制
# 仅本地试调、未配有效密钥时:
# YC_INVOKE_SKIP_AUTH=1代码内显式配置(与环境变量二选一):
javascript
import { createClient } from 'yc-runtime-sdk';
const yc = createClient({
baseUrl: 'http://localhost:8081/yc', // 来源见上表 YC_BASE_URL
projectId: 'cfeb9dd64869922937499a5e453e6f34', // 来源见上表 YC_PROJECT_ID
accessKey: 'ycdk_...', // 来源见上表 YC_ACCESS_KEY
skipAuth: false,
});java
YcRuntimeClient yc = new YcRuntimeClient(
YcRuntimeConfig.builder()
.baseUrl("http://localhost:8081/yc")
.projectId("cfeb9dd64869922937499a5e453e6f34")
.accessKey("ycdk_...")
.build()
);4.2 平台「服务配置」与鉴权参数对应关系
在 sky-curtain → 服务器管理 → 服务配置 中的配置,决定您应在后端使用哪类参数:
| 平台配置项 | 平台位置 | 您在后端应使用的参数 | 说明 |
|---|---|---|---|
| 启用运行时鉴权 | 服务配置 → 动态 API 鉴权开关 | 有效时须配 YC_ACCESS_KEY 或 userJwt 或 RSA | 关闭时运行面可不校验(不推荐生产) |
| 校验方式 = 接入密钥(换 Token) | 服务配置 → 校验方式 PLATFORM_INVOKE | YC_ACCESS_KEY | SDK 自动 POST .../_auth/token + Bearer |
| 校验方式 = 项目 JWT | 服务配置 → PROJECT_JWT + JWT 签名密钥 | userJwt(每次调用传入或 YC_USER_JWT) | 签名密钥须与业务 JWT_SECRET 完全一致(example-1 的 JWT_SECRET) |
| 校验方式 = RSA 私钥签 JWT | 服务配置 → CLIENT_RSA + 生成密钥对 | YC_CLIENT_RSA_PRIVATE_KEY | 私钥来自生成弹窗;Node 需 jsonwebtoken |
| 接入密钥明文 | 服务配置 → 「生成接入密钥」弹窗 | YC_ACCESS_KEY | 仅一次;丢失需重新生成 |
| RSA 私钥 PEM | 服务配置 → 「生成 RSA 密钥对」弹窗 | YC_CLIENT_RSA_PRIVATE_KEY | 仅一次 |
| JWT 签名密钥 | 服务配置 → 「JWT 签名密钥」输入框 | 写入业务 JWT_SECRET(非 SDK 环境变量名) | 用于签发 userJwt,不是 YC_ACCESS_KEY |
| IP 白名单 | 服务配置 / 对外接入 | 无单独 SDK 变量 | 限制调用平台 API 的服务器出口 IP;在平台填写 BFF 公网 IP |
不要混淆:
| 容易搞错 | 实际来源 |
|---|---|
| 天幕控制台登录后的 Token | 仅用于操作 sky-curtain 管理接口,不能作为 YC_ACCESS_KEY 或 userJwt 调运行面 |
ycak_xxxxxxxx 占位符 | 文档示例,无效;须换成服务配置生成的 ycdk_... |
换 Token 返回的 accessToken | 由 SDK 自动换取并缓存,无需手写进 .env |
4.3 动态 API 调用参数
| 参数 | 用途 | 获取来源(从哪里拿) | 填写位置 |
|---|---|---|---|
modelKey | 路径中的模型标识,如 .../dynamic-api/v1/{projectId}/{modelKey} | sky-curtain → 服务器管理 → 数据模型:对某表发布动态 API 后,一般为表名(如 products)。或 API 管理 列表中「products · 分页列表」里的 products。与连接配置 ID、模型内部 UUID 不同,调用时用 modelKey 字符串。 | yc.dynamic.list('products', ...) 第一个参数 |
projectId | 路径中的项目 ID | 同 §4.1 YC_PROJECT_ID | 已由 SDK 从环境变量注入,调用时无需再传 |
id | 单条详情 / 更新 / 删除的主键 | 业务数据:列表接口返回的 id 字段,或您业务库主键。新路径约定下通过 ?id= 或请求体 id 传递(不再依赖 .../{id} 路径段;旧写法仍兼容)。 | yc.dynamic.get('products', id) 等;或 fetch + ?id= |
currentPage | 分页页码 | 业务约定:SDK/平台分页协议字段,默认从 1 开始;非平台某页面复制。 | body.currentPage |
pageSize | 每页条数 | 业务约定:常用 10~200,须 ≤ 平台限制(通常 200)。 | body.pageSize |
params | 查询条件对象 | 平台发布配置:在 数据模型 → 发布 API 时配置的「查询参数字段」白名单内的键(如 status、name)。键名须与发布时命名策略一致(camelCase / snake_case,example-1 用 YC_DYNAMIC_NAMING 对齐)。 | body.params |
body(create/put) | 写入字段 | 平台数据模型字段 + 发布允许的写字段;字段名与库表/模型一致,受命名策略影响。 | yc.dynamic.create / put 的 body |
JSON 类型列(如 images 图集):body 中可直接传 JSON 数组或对象,运行面会自动序列化后写入 MySQL JSON 列,无需在 SDK 或业务代码里先 JSON.stringify。详见 数据模型 §5.4。 | userJwt | 动态 API Bearer(PROJECT_JWT 模式) | 业务登录接口:用户登录成功后,您的后端签发的 JWT。example-1:POST /api/login 返回的 data.token,由 JWT_SECRET 签名。须与平台服务配置里 JWT 签名密钥 一致。 | 每次调用第三参,或 YC_USER_JWT |
动态 API 完整 URL 组成(便于核对来源):
text
{YC_BASE_URL}/dynamic-api/v1/{YC_PROJECT_ID}/{modelKey}/{operationSuffix}
↑ ↑ ↑ ↑
运维/本地8081 地址栏项目ID API管理/表名 发布配置中的路径后缀默认后缀(可在发布配置中修改):
| 操作 | 默认后缀 | 默认方法 |
|---|---|---|
| 分页列表 | /list | POST |
| 详情 | /get | GET |
| 创建 | /create | POST |
| 全量更新 | /update | PUT |
| 删除 | /delete | DELETE |
详情 / 更新 / 删除的主键:GET|PUT|DELETE .../get?id=1 或 body { "id": "1" }。
SDK 便捷方法与兼容:
yc.dynamic.list / get / create / put / delete仍使用短路径(如.../products、.../products/{id}),平台运行面会兼容映射到已发布配置。- 若你在发布配置里改过路径或方法,或需与 API 管理展示完全一致,请用
yc.dynamic.fetch并传入发布配置中的后缀与方法,例如:
javascript
await yc.dynamic.fetch('products', '/list', { method: 'POST', body: { currentPage: 1, pageSize: 20, params: {} } });
await yc.dynamic.fetch('products', '/get', { method: 'GET', /* 配合 ?id= 见 dynamicFetch 实现 */ });以 数据模型 → 发布 → 接口配置 或 API 管理 中显示的 path、method 为准。
4.4 自定义 API 调用参数
| 参数 | 用途 | 获取来源(从哪里拿) | 填写位置 |
|---|---|---|---|
apiKey | 路径中的 API 标识 | sky-curtain → 服务器管理 → 自定义 API:列表中的 「API 标识」/ apiKey(如 order_summary、goods-list)。须状态为 已发布;未发布调用会失败。 | yc.custom.invoke('apiKey', body) 第一个参数 |
projectId | 路径中的项目 ID | 同 YC_PROJECT_ID | SDK 已注入 |
body | POST 请求体 | 平台自定义 API 编排:在编辑器中定义的入参结构;参考该 API 的「试调」请求体或编排说明。无统一固定字段,按每个 apiKey 不同。 | invoke 第二参数 |
method | HTTP 方法 | 自定义 API 发布配置 中该 API 的方法(多为 POST);SDK 默认 POST,可选 GET 等。 | invoke 第三参 opts.method |
自定义 API URL:
text
{YC_BASE_URL}/custom-api/v1/{YC_PROJECT_ID}/{apiKey}鉴权:与动态 API 共用 YC_ACCESS_KEY 换 Token(服务配置统一鉴权开启时)。
4.5 example-1 演示工程参数对照
便于对照 test-projects/example-1/backend/.env:
| 环境变量 | example-1 中的值从哪来 |
|---|---|
YC_BASE_URL | 本地 yc_user_service 默认 http://localhost:8081/yc |
YC_PROJECT_ID | 文档示例 cfeb9dd64869922937499a5e453e6f34,须改成您 sky-curtain 地址栏中的项目 ID |
YC_ACCESS_KEY | 服务配置生成;示例里 ycak_xxxxxxxx 为占位,实际会走 用户登录 JWT |
JWT_SECRET | 业务自建 example1-change-me-in-production,须与服务配置 JWT 签名密钥 一致 |
YC_USE_DYNAMIC_API | 业务自建 开关,非 SDK 变量 |
YC_DYNAMIC_NAMING | 与平台数据模型发布时的 全局命名策略 一致 |
验证脚本:cd backend && npm run verify:sdk。
4.6 参数获取路径速查(按平台菜单)
text
sky-curtain 登录
└─ 进入目标应用(记下地址栏 projectId → YC_PROJECT_ID)
└─ 服务器管理
├─ 连接配置 → 数据源(与 SDK 无直接 env,平台内部用)
├─ 数据模型 → 发布 API → modelKey(通常=表名)
├─ API 管理 → 核对 modelKey、发布状态
├─ 自定义 API → apiKey、body 结构、发布
└─ 服务配置 → YC_ACCESS_KEY / JWT密钥 / RSA私钥、鉴权方式
yc_user_service 部署地址 + /yc → YC_BASE_URL
您的业务后端 .env / 配置中心 → 写入上述变量,勿写入前端5. 鉴权方式说明
各鉴权相关参数在平台的获取位置见 §4.2。
SDK 按以下优先级选择凭证(与平台「服务配置」一致):
| 方式 | 配置 | 适用 API | 说明 |
|---|---|---|---|
| 接入密钥 + 平台 Token | YC_ACCESS_KEY | 动态 + 自定义 | 生产推荐;密钥仅存后端 |
| 试调跳过 | YC_INVOKE_SKIP_AUTH=1 | 动态 + 自定义 | 仅开发;请求带试调头 |
| 业务 JWT | YC_USER_JWT 或单次 userJwt | 主要为动态 API | 平台校验方式为 PROJECT_JWT 时,传用户登录签发的 JWT |
| RSA 私钥签 JWT | YC_CLIENT_RSA_PRIVATE_KEY(Node) | 动态 API | 平台为 CLIENT_RSA 时;Java SDK 首版请用 accessKey |
开启接入密钥后,换 Token 会先请求:
POST {base}/dynamic-api/v1/{projectId}/_auth/token- 若失败再尝试
POST {base}/custom-api/v1/{projectId}/_auth/token
统一鉴权开启时,两条路径等效。
6. 动态 API 使用
modelKey、params、userJwt 等参数来源见 §4.3。modelKey 与平台发布一致(常见为表名,如 products)。
6.1 Node.js
javascript
import { createClientFromEnv } from 'yc-runtime-sdk';
const yc = createClientFromEnv();
// 分页列表(POST 根路径,body 含 currentPage / pageSize)
const page = await yc.dynamic.list('products', {
currentPage: 1,
pageSize: 20,
params: {}, // 可选:平台配置的查询条件
});
// 单条
const row = await yc.dynamic.get('products', 1);
// 新增
await yc.dynamic.create('products', { name: '商品A', sku: 'SKU001', price: 99 });
// 更新
await yc.dynamic.put('products', 1, { name: '商品A-改' });
// 删除
await yc.dynamic.delete('products', 1);
// 通用请求(自定义 path、方法)
const raw = await yc.dynamic.fetch('products', '/batch', {
method: 'POST',
body: { ids: [1, 2, 3] },
});PROJECT_JWT:用户已登录,把业务 JWT 传给动态调用:
javascript
const list = await yc.dynamic.list('products', { currentPage: 1, pageSize: 10 }, userJwt);6.2 Java
java
YcRuntimeClient yc = YcRuntimeClient.fromEnv();
Map<String, Object> page = yc.dynamicList("products", Map.of(
"currentPage", 1,
"pageSize", 20
));
Object row = yc.dynamicGet("products", 1);
yc.dynamicCreate("products", Map.of("name", "商品A", "sku", "SKU001", "price", 99));
yc.dynamicUpdate("products", 1, Map.of("name", "商品A-改"));
yc.dynamicDelete("products", 1);
// PROJECT_JWT:第四个参数传用户 JWT
yc.dynamicFetch("products", "", "POST", Map.of("currentPage", 1, "pageSize", 10), userJwt);6.3 列表请求体与路径说明
分页列表默认 POST 到 {base}/dynamic-api/v1/{projectId}/{modelKey}/list:
http
POST /yc/dynamic-api/v1/{projectId}/products/list
Content-Type: application/json
{
"currentPage": 1,
"pageSize": 20,
"params": {}
}其它标准接口(默认路径):
| 操作 | 方法(默认) | 路径示例 |
|---|---|---|
| 详情 | GET | .../products/get?id=1 |
| 创建 | POST | .../products/create + body |
| 全量更新 | PUT | .../products/update?id=1 + body |
| 删除 | DELETE | .../products/delete?id=1 |
以上 method、path 均可在发布配置中修改。旧版 POST .../products(根路径)、GET .../products/{id} 仍受平台兼容层支持;SDK 便捷方法 list/get/... 走短路径即可,详见 §4.3。
成功时 SDK 返回平台响应里的 data 字段(已解包,不再包含外层 code/message)。
6.4 在 Express 中封装(Node 示例)
javascript
import express from 'express';
import { createClientFromEnv } from 'yc-runtime-sdk';
const app = express();
const yc = createClientFromEnv();
app.get('/api/products', async (req, res) => {
try {
const page = await yc.dynamic.list('products', {
currentPage: Number(req.query.page) || 1,
pageSize: Number(req.query.size) || 20,
});
res.json(page);
} catch (e) {
res.status(e.status || 500).json({ message: e.message, code: e.code });
}
});7. 自定义 API 使用
apiKey、body 获取来源见 §4.4。
7.1 Node.js
javascript
const yc = createClientFromEnv();
const result = await yc.custom.invoke('order_summary', {
userId: 123,
dateFrom: '2026-01-01',
});
// 非 POST 时可指定 method
await yc.custom.invoke('export_report', null, { method: 'GET' });7.2 Java
java
Object result = yc.customInvoke("order_summary", Map.of(
"userId", 123,
"dateFrom", "2026-01-01"
));自定义 API 的请求体、响应结构由平台编排决定,SDK 只负责鉴权与 HTTP。
8. 错误处理
平台统一响应格式:
json
{ "code": 200, "message": "...", "data": { } }失败时 code !== 200 或 HTTP 非 2xx,SDK 抛出异常:
Node.js — Error,附加字段:
message:平台返回说明code:业务码status:HTTP 状态platform:原始 JSON(便于排查)
javascript
try {
await yc.dynamic.list('products', { currentPage: 1, pageSize: 10 });
} catch (e) {
console.error(e.message, e.code, e.status);
}Java — YcRuntimeException:
java
try {
yc.dynamicList("products", Map.of("currentPage", 1, "pageSize", 10));
} catch (YcRuntimeException e) {
System.err.println(e.getMessage() + " code=" + e.getCode());
}8.1 常见错误对照
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 缺少鉴权凭证 | 未配 YC_ACCESS_KEY 且未开 YC_INVOKE_SKIP_AUTH | 在服务配置生成密钥并写入环境变量 |
| 接入密钥无效 | 密钥错误或已轮换 | 在平台重新生成并更新后端配置 |
| Token 已过期 | 时钟偏差或缓存异常 | 重启进程;SDK 会自动重新换 Token |
| 401 鉴权凭证无效 | PROJECT_JWT 时 JWT 密钥与平台不一致 | 对齐 JWT_SECRET 与平台「JWT 签名密钥」 |
| 403 IP 不在白名单 | 服务配置启用了 IP 白名单 | 将服务器出口 IP 加入白名单 |
| 自定义 API 未发布 | 仅保存未发布 | 在平台点击发布后再调用 |
| 动态 API 404 | modelKey 未发布或拼写错误 | 在 API 管理核对 modelKey |
Cannot create a JSON value... binary | JSON 列未按平台规范写入 | 传数组/对象;重启 yc_user_service 并重新发布模型 → 数据模型 FAQ 10.7 |
字段不能为空: published_at(等) | create 显式传了 null 或字段不可写 | 升级运行面 + 可写字段排除该列 → 动态 API FAQ 11.19 |
天幕动态 API 调用失败: ... | 运行面校验/ JDBC 错误被 BFF 包装 | 看冒号后原文;控制台试调对比 → 动态 API FAQ 11.20 |
| 试调通、SDK 调用仍失败 | YC_BASE_URL / YC_PROJECT_ID 与试调不一致 | 核对 .env 指向 8081 /yc,不是前端 3000 |
9. 安全注意事项
YC_ACCESS_KEY仅放在用户后端,不要写入前端、移动端、公开仓库。- 生产环境关闭
YC_INVOKE_SKIP_AUTH。 - 平台「服务配置」可配置 IP 白名单、限流;与 Token 为叠加关系。
- 终端用户登录态由您的业务系统校验;平台 Token 只表示「该项目后端有权调用运行面」。
10. API 速查
Node.js
| 方法 | 说明 |
|---|---|
createClientFromEnv() | 从环境变量创建客户端 |
createClient(options) | 显式配置 |
yc.dynamic.list(modelKey, body, userJwt?) | 分页列表 |
yc.dynamic.get(modelKey, id, userJwt?) | 查询单条 |
yc.dynamic.create(modelKey, body, userJwt?) | 创建 |
yc.dynamic.put(modelKey, id, body, userJwt?) | 更新 |
yc.dynamic.delete(modelKey, id, userJwt?) | 删除 |
yc.dynamic.fetch(modelKey, suffix, opts) | 通用调用 |
yc.custom.invoke(apiKey, body, opts?) | 自定义 API |
Java
| 方法 | 说明 |
|---|---|
YcRuntimeClient.fromEnv() | 从环境变量创建 |
YcRuntimeClient.create(baseUrl, projectId, accessKey) | 快捷构造 |
dynamicList / dynamicGet / dynamicCreate / dynamicUpdate / dynamicDelete | 动态 API CRUD |
dynamicFetch(modelKey, suffix, method, body, userJwt) | 通用调用 |
customInvoke(apiKey, body) | 自定义 API |
11. 与演示工程对照
仓库 test-projects/example-1/backend 内有手写客户端(yc-client.js、yc-dynamic-client.js),逻辑与 SDK 等价。迁移步骤:
- 安装
yc-runtime-sdk(npm install yc-runtime-sdk) - 用
createClientFromEnv()替换手写fetch+ 换 Token - 保留原有
.env变量名即可(YC_BASE_URL、YC_PROJECT_ID、YC_ACCESS_KEY)
12. 常见问题(业务后端与动态 API 联调)
本节汇总业务 BFF 通过 SDK 调天幕时的典型问题;平台侧配置细节见 数据模型 FAQ 与 动态 API FAQ。
12.1 报错 No static resource api/...(Spring 404)
现象:访问业务后端 GET /api/admin/posts 等返回:
text
No static resource api/admin/posts原因:这是 业务自有 Controller 路由,不是天幕动态 API。多为 业务后端未重启、未编译进新代码,或 URL 写错。
处理:
- 重新编译并 重启业务后端(如
xin-lv-server)。 - 用
GET /api/health确认进程已是新版本。 - 管理端接口路径以项目内 Controller 为准;数据表 CRUD 仍走
yc.dynamic.create('user_post', ...)等形式。
与「动态 API 404」不同:后者是 8081 上 modelKey 未发布,见 §8.1。
12.2 是否必须在 BFF 里 JSON.stringify 或去掉 published_at?
一般不需要(运行面已升级并重新发布后):
- JSON 列:SDK
dynamic.createbody 直接传数组/对象。 published_at:create 不传;或传null(新版运行面视为未传)。
若暂时无法升级天幕,可临时在 BFF 处理,长期应改 平台配置 + 重启 yc_user_service。见 动态 API FAQ 11.22。
12.3 发帖成功,App 发现流看不到?
多为 业务审核规则,不是 SDK 故障:
- create 时
status为待审(如2),list 只查已发布(如status=1)。 - 须在管理端审核通过并写入
published_at后才会出现在公开列表。
数据模型字段分工见 数据模型 FAQ 10.10。
12.4 联调顺序(推荐)
- 平台试调 create/list 通过
- SDK 或
curl经 BFF 环境变量直连天幕验证 - 再接业务前端
完整清单:动态 API FAQ 11.21。
13. 相关文档
- rely-ons/README.md — 包索引与快速开始
- yc-runtime-sdk/README.md — Node 包说明
- yc-runtime-sdk-java/README.md — Java 包说明
- 动态API · 用户接入与鉴权 — 鉴权模式选型
- 自定义API · 使用说明 — 控制台配置与 BFF 对接