快速开始 · JS / 浏览器
快速开始 · JS / 浏览器
5 分钟在浏览器接入 LinkSoul JS SDK。核心与原生 SDK 一致,但因浏览器限制,鉴权必须经过一个同源服务端代理——这是本页与原生快速开始最大的不同。
环境要求
| 项 | 要求 |
|---|---|
| 包 | linksoul-agentsdk(ESM) |
| 运行时 | 现代浏览器;安全上下文(https 或 localhost),否则拿不到麦克风、crypto.randomUUID 也不可用 |
| 打包器 | Vite / webpack / esbuild 等支持 ESM 的工具 |
| 服务端 | 任意能算 HMAC-SHA256 并代理 WebSocket 的后端(示例用 Node server.mjs) |
安装与导入
bash
npm install linksoul-agentsdk
ts
import {
createAgentSdk,
AgentEventType,
type TeleopSession,
} from 'linksoul-agentsdk';
服务端代理:为什么必须
浏览器的 WebSocket 构造器只接受 url 和 protocols,无法设置 X-App-Id / X-Signature 等鉴权头,也发不了协议级 Ping 帧。因此 JS SDK 把这两件事交给一个同源服务端:
text
浏览器 你的服务端 灵心网关
│ POST /api/ws-auth │ │
│ ───────────────────────────→ │ 计算 HMAC-SHA256 │
│ │ 用 X-App-* 头连上游 ───────────→ │
│ { url: ws://.../ws?t=票据 } │ ←────────────── 握手成功 ─────── │
│ ←─────────────────────────── │ │
│ new WebSocket(本地代理URL) │ │
│ ───────────────────────────→ │ ←── 双向透传 ────────────────→ │
appSecret只存在于服务端;浏览器只拿到一个一次性票据换来的本地代理 URL;- 服务端把 SDK 发出的 JSON
{type:"ping"}转成 WebSocket 协议级 Ping,把网关的协议级 Pong 合成 JSON{type:"pong"}回传,从而让 SDK 的 keep-alive 在浏览器下也能工作。
服务端签名要点(Node 示例)
js
import { createHmac, randomUUID } from 'node:crypto';
const timestamp = String(Date.now());
const nonce = randomUUID().replace(/-/g, '');
const signature = createHmac('sha256', appSecret)
.update(`GET\n${pathname}\n${timestamp}\n${nonce}`)
.digest('hex');
// 用这些头连上游网关:
// X-App-Id, X-App-Key, X-Timestamp, X-Nonce, X-Signature, X-Callback-Types
签名串固定为 HMAC-SHA256(appSecret, "GET\n{pathname}\n{timestamp}\n{nonce}")(hex)。完整可运行代理见示例 agentsdk_for_js/example/teleop/server.mjs。
完整接入代码
ts
import { createAgentSdk, AgentEventType } from 'linksoul-agentsdk';
const appId = '<灵心开放平台应用 appId>';
const agentId = '<目标机器人 agentId>';
// 1. 创建 SDK:authProvider 每次连接 / 重连时被调用,返回已签名的代理 URL
const sdk = createAgentSdk(appId, {
authProvider: async () => {
const res = await fetch('/api/ws-auth', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
url: 'wss://open.agibot.com/api/V1/open-portal/app/wss/agent-sdk',
appId,
// appKey / appSecret 只在服务端读取,切勿写进前端
}),
});
const { url } = await res.json();
return { url }; // 指向本地代理,如 ws://localhost:8787/api/ws?t=票据
},
reconnect: true, // 断线自动重连(固定 3s 间隔)
});
// 2. 监听下行消息(所有 ACK 都在这里)
sdk.on('message', ({ data }) => {
const msg = JSON.parse(typeof data === 'string' ? data : '');
if (msg.type === AgentEventType.TeleopEnterAck) {
// msg.code === 0 表示进入成功
}
});
sdk.on('connected', () => console.log('connected'));
sdk.on('disconnected', ({ willReconnect }) => console.log('closed', willReconnect));
// 3. 建立连接(内部会调用 authProvider)
await sdk.connect();
// 4. 之后创建遥操会话,完整流程见「超视距遥操指南」
const session = sdk.createTeleopSession({ agentId });
session.enter();
单例注意事项
createAgentSdk(appId, ...) / AgentSdk.create(appId, ...) 按 appId 维护单例:同 appId 重复调用返回同一个实例。切换账号或需要全新连接时,先 sdk.release()(关闭并从单例表移除)再重新 createAgentSdk。
常见问题
getUserMedia报错 / 拿不到麦克风:确认页面运行在 https 或 localhost 下(安全上下文)。- 连接立即失败:多半是
authProvider返回的 URL 无效或服务端签名失败;先单独用curl/ Postman 打通/api/ws-auth。 crypto.randomUUID is not a function:非安全上下文下不可用;SDK 内部已回退到crypto.getRandomValues/Math.random,但仍建议部署到 https。- 重连后要重新
enter吗:要。重连是连接层行为,遥操会话状态不会自动恢复;在connected事件里重新走createTeleopSession → enter。