阅读主题
H5 会话、刷新与退出
适用版本:v0.2.1。前置为完成 快速接入,并由游戏后端返回完整 SessionResponse。
默认内存与显式持久化
不配置 storage 时,SDK 仅保存内存会话,刷新后丢失。传入 storage: sessionStorage 后,登录成功写入标签页存储,键按平台 API origin 与 App ID 隔离。getSession() 返回副本,不应通过修改副本改变登录身份。
构造实例和 init() 都不会自动恢复。启动时显式调用 await sdk.restoreSession():SDK 读取候选,经 /api/me 验证后才发布 session 事件和公开身份;并发恢复共享一次操作。存储适配器接口为:
ts
interface SessionStorageAdapter {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
}sessionStorage 不是 HttpOnly cookie,也不是长期自动登录。宿主需同时保护页面脚本与自己的游戏会话;平台令牌不要放在 URL、日志或跨窗口广播中。
恢复失败时的正确界面
ts
import { ApiError } from '@starlight/sdk';
import { sdk } from './sdk';
export async function recover() {
try {
const session = await sdk.restoreSession();
return session
? { state: 'authenticated' as const, session }
: { state: 'anonymous' as const };
} catch (error) {
// 不调用 clearSession():暂时断网不应删除有效的存储候选。
return {
state: 'retry' as const,
message: error instanceof ApiError ? error.message : '恢复失败,请重试',
};
}
}| 情况 | SDK 行为 | 宿主预期 |
|---|---|---|
| 没有候选、候选损坏或本地到期 | 返回 null,无效候选清除 | 显示登录入口 |
/api/me 验证成功 | 保存最新 user/role,返回会话、发布事件 | 再恢复角色与游戏连接 |
| 已识别会话失效的 401 | 清除会话候选,返回 null | 重新登录 |
| 断网、超时、服务器异常 | 抛出错误,保留尚未验证的存储候选 | 显示重试,不展示已登录身份 |
| 恢复过程中发生切号/清会话 | 旧恢复结果不能覆盖新会话 | 以最新 session 事件为准 |
已识别的会话错误为 SESSION_EXPIRED、SESSION_REVOKED、UNAUTHENTICATED、INVALID_SESSION(HTTP 401)。INVALID_CREDENTIALS 不会因“也是 401”就清掉当前账号。恢复候选验证失败与业务请求失败必须区别处理。
退出、取消与切号
ts
import { sdk } from './sdk';
const unsubscribe = sdk.on('session', session => {
if (!session) {
// 此处断开宿主旧角色连接、聊天订阅,并清空账号相关页面状态。
}
});
export async function leaveAccount() {
try { await sdk.logout(); }
catch { /* 本地已退出;提示服务端撤销未确认,允许玩家稍后检查设备。 */ }
}
export function cancelLoginDialog() { sdk.cancelLogin(); }
export async function changeAccount() { await sdk.switchAccount(); }
export function disposeBindings() { unsubscribe(); }logout() 先发起捕获旧令牌的撤销请求,立即清本地会话与存储;即使请求失败,也不会把本地身份恢复。clearSession() 只清本地,不发送服务端撤销。cancelLogin() 使当前登录事务失效,不是退出当前已登录账号。switchAccount() 执行退出,并在无会话时发送 center: {view:'login'};宿主仍需自己打开登录 UI。
SDK 不向外部游戏推送封禁/退出事件,也没有自动清除游戏自有 cookie。你的游戏后端必须决定平台会话撤销如何影响自身会话。
设备管理
ts
const { items } = await sdk.sessions();
const other = items.find(item => !item.current);
// 在宿主确认弹窗取得用户确认后执行:
if (other) await sdk.revokeSession(other.id);
// 另一项独立操作:await sdk.revokeOtherSessions();设备列表跨本人游戏展示有效会话,不包含 token 或摘要。公开 id 是撤销句柄,不能用于登录。撤销当前设备会清本地会话;撤销其他设备后,对方下次平台请求被拒绝。设备描述来自客户端信息,不是不可伪造设备指纹。
上线前至少验证:登录后刷新、退出后刷新、被踢后刷新、恢复中断网再重试、不同 App ID/origin 隔离、切号后旧请求返回,以及游戏自有会话一起退出。错误和方法细节见 API 参考。
到期的内存会话
当前内存会话已经到期时,restoreSession 会先清除旧身份并发布 null,不会一边返回未登录一边让 getSession 保留旧 token,也不会重新写回过期候选。此规则不改变网络失败保留有效候选的行为。
HTTP 403 的 ACCOUNT_RESTRICTED / APP_UNAVAILABLE 也属于终止状态:清除当前会话或恢复候选。普通 ROLE_FORBIDDEN 等业务403不清登录;旧请求不得清除新账号。
v0.2.1 的取消与存储边界
timeoutMs(默认 15 秒)限制整次登录,包括宿主 exchange。cancelLogin() 立即拒绝当前登录为 LOGIN_CANCELLED;超时为 TIMEOUT。SDK 丢弃迟到交换结果;宿主交换函数中的网络和业务副作用仍需宿主自己管理。
登录进行中不会恢复旧的存储候选。存储临时读取失败返回 null,保留候选供后续重试。显式退出后的删除失败不会在同一 SDK 实例恢复旧凭证;存储本身不可写时无法保证跨刷新擦除,宿主应完成服务器撤销并向用户说明当前浏览器限制。
事件观察者收到各自的会话副本;异常不阻断其他观察者。回调内切号或退出会停止旧会话继续通知。自定义存储回调内取消时,SDK 回滚本次候选,不覆盖新的账号。