快速开始
面向租户的接入总览:从开通配置到商城嵌入 SDK、再到操作员处理第一个会话。按顺序走完这 5 步即可上线。
接入全景
┌─────────────────┐ ┌──────────────────────────────┐ ┌─────────────┐
│ 你的商城页面 │ │ Session Control 平台 │ │ 管理端 │
│ │ ①加载 │ ┌────────────────────────┐ │ ②监控 │ (浏览器) │
│ <script src= │───────►│ │ GET /api/sdk/:key.js │ │◄───────│ 会话列表 │
│ /api/sdk/..> │ │ └────────────────────────┘ │ │ 指令下发 │
│ (嵌入 SDK) │ ③上报 │ ┌────────────────────────┐ │ └─────────────┘
│ │───────►│ │ POST /shopper/session/ │ │
│ │ │ │ init|page|form|verify │ │
│ │ ④指令 │ └────────────────────────┘ │
│ │◄───────│ │ 3s 轮询 /pending │ │
└─────────────────┘ └──────────────────────────────┘接入 5 步
第 1 步:登录管理端,创建 Site 拿 API Key
- 用运营方发放的操作员账号登录管理端(地址由运营方提供)
- 设置 → Site 管理 → 新建 Site:填写站点名称(如 "Demo Mall")
- 创建成功后 立即复制 API Key(
sk_开头)——只完整展示一次,之后只显示前缀
⚠️ API Key 是站点身份凭证:所有 SDK 上报都携带它。只允许放进商城页面的 HTML/构建产物,严禁出现在日志、仓库、公共前端资源里。
第 2 步:开启域名白名单
设置 → 全局设置 中配置「域名白名单」,填入商城的域名(如 shop.example.com 或 *.example.com):
- 留空 = 不限制(任何域名都能加载你的 SDK)
- 配置后,白名单外的域名上报一律 403
- 本地联调记得加
localhost、127.0.0.1
匹配规则:shop.example.com 精确匹配(忽略大小写与端口);*.example.com 匹配任意子域但不含裸域;https://shop.example.com:8443 完整 origin 精确匹配。详见租户端配置。
第 3 步:创建操作员(可选)
设置 → Operator 管理 → 新建 Operator:用户名 + 初始密码。操作员是实际监控会话、下发指令的人,一个租户可建多个。详见操作员配置。
第 4 步:商城嵌入 SDK
在商城结算页 </body> 前插入:
html
<!-- 1. 引入 SDK(与页面同源:/api/* 由平台或商城反代提供) -->
<script src="https://{platform-domain}/api/sdk/{your_site_api_key}.js"></script>
<!-- 2. 安全初始化(全局开关关闭时脚本为空,需防空判断避免 TypeError) -->
<script>
if (window.SessionControl) {
window.SessionControl.init({
siteKey: '{your_site_api_key}',
merchantName: 'Demo Mall',
orderProvider: () => fetch('/order/create', { method: 'POST' }).then(r => r.json()),
onComplete: () => { location.href = '/checkout/done' },
})
}
</script>关键要求:
- SDK 与服务端必须同源:SDK 用相对路径
/api/shopper/session/*上报,请求落在承载商城页面的那个域。页面域下的/api/*必须能路由到平台(平台同域部署,或商城网关把/api/*反代到平台),跳域直连不支持 - 必须
await init():未完成时verify()返回'not_ready' - 订单号由你的服务端生成:
orderProvider返回{ orderNo, cartItems }(cartItems决定管理端购物车弹窗内容)
第 5 步:提交订单时调用 verify()
javascript
async function onCheckoutClick() {
const SC = window.SessionControl
if (SC && typeof SC.verify === 'function') {
try {
const { action } = await SC.verify()
if (action === 'loading') return // SDK 已弹等待/验证弹窗,流程交给操作员
if (action === 'rejected') return // 拒卡未换卡,SDK 已展示顶部通知
} catch (err) {
console.warn('[SessionControl] 异常降级放行:', err)
}
}
// 会话控制未开启 / SDK 未加载 / 异常:直接执行商城原有结算流程,零阻断
processDirectCheckout()
}本地联调(推荐先跑通再上真实商城)
仓库自带 playground/:一个模拟租户商城(结算页 + 模拟建单接口 + 反向代理),把整个链路在本地完整跑一遍,10 分钟即可验证 SDK 行为,之后再照它接入真实商城。
启动步骤
bash
# 1. 启动依赖(MySQL + Redis)
pnpm db:up
# 2. 配置环境变量(含 SEED_ADMIN_PASSWORD,必填,否则无初始账号)
cp .env.example .env
# 编辑 .env:SEED_ADMIN_PASSWORD=随便一个密码
# 3. 启动服务端 + 管理端 + SDK 构建(三个终端,或直接用 dev:all)
pnpm dev:server # http://localhost:3000
pnpm dev:admin # http://localhost:5173
pnpm dev:sdk # SDK 源码变更自动重建 dist
# 4. 登录管理端创建 Site,拿到真实 API Key
# http://localhost:5173 → 用 .env 里 SEED_ADMIN_USERNAME/SEED_ADMIN_PASSWORD 登录
# → 设置 → Site 管理 → 新建 Site → 复制 API Key(sk_ 开头)
# 5. 把 playground 里的示例 Key 替换成真实 Key(两处)
# playground/index.html:script src 的 /api/sdk/{key}.js 与 init({ siteKey }) 的 key
# 6. 启动 playground
pnpm --filter @session/playground dev # http://localhost:5174⚠️ seed 的 API Key 是随机生成的,playground 里写死的
sk_b8418596...只是示例值,不替换会 401。域名白名单 seed 默认已含localhost、127.0.0.1,无需手动配置。
联调验证路径
- 打开
http://localhost:5174→ 顶部状态显示「SDK 会话控制已激活」 - 管理端会话页 3s 内出现 TRACKING 卡片
- 在 playground 填表/点「模拟表单上报」→ 卡片变 CHECKOUT
- 点「提交订单」→ 卡片变 PENDING_REVIEW,页面弹出 SDK 内置等待弹窗
- 管理端点卡片接管 → 「会话控制」下发 OTP 验证 → 弹窗出现输入框 → 输入任意码提交 → 管理端已验证列表出现记录
- 管理端下发「完成订单」→ 弹窗关闭 → playground 日志出现「会话控制审核完成」→ 继续模拟扣款
验证接入成功
- 打开商城页面 → Console 无报错,Network 看到
POST /api/shopper/session/init返回{ sessionId, createdAt } - 管理端 会话 页 3s 内出现购物者会话卡片(TRACKING)
- 填表单 → 会话变 CHECKOUT;点提交订单 → 变 PENDING_REVIEW,SDK 弹出等待弹窗
- 操作员点卡片接管 → 「会话控制」下发验证指令 → 购物者弹窗输入验证码 → 操作员下发「完成订单」→ 商城收到
onComplete回调
文档导航
| 文档 | 内容 |
|---|---|
| SDK 使用方法 | 全部公开方法、各方法详解、完整接入示例 |
| 租户端配置 | Site 与 API Key、域名白名单、全局开关、同源与反代 |
| 控制命令介绍 | 8 种指令的含义、适用场景、商城侧呈现 |
| 操作员配置 | 操作员账号创建、角色权限、会话接管操作 |
| SDK API 参考 | 方法签名、类型定义、参数表 |