外观
第三方存档读取
第三方应用在玩家授权后可以读取该玩家的存档数据。读取流程分为两步:
- 调用
get查询存档元信息(是否存在、最后更新时间、来源设备) - 调用
pull获取临时下载链接,再从对象存储节点直接下载存档文件
存档文件直接从对象存储节点传输到你的服务端,不经过 Notanote 服务器中转,兼顾速度与带宽。
前置条件
调用本组接口前,请确认以下事项:
- 已完成 WebAuth 网页授权,拿到玩家的
access_token和name(展示模式下从授权码{name}.{token}按第一个.拆分获得) - 你的
TID和SecretKey已正确配置
授权即开启存档访问
玩家在 Notanote 授权页点击「确认授权」后,「允许第三方访问存档」开关会自动打开,无需引导玩家手动到客户端设置。因此只要玩家完成授权,你的应用即可直接调用存档接口。
数据流向
mermaid
sequenceDiagram
participant App as 你的服务端
participant Nano as Notanote API
participant S3 as 对象存储节点
App->>Nano: POST /third-party/save/get(查询存档元信息)
Nano->>Nano: 校验 TID + SecretKey
Nano->>Nano: 校验 name + access_token
Nano-->>App: 返回存档元信息(是否存在、最后更新时间、来源设备)
App->>Nano: POST /third-party/save/pull(拉取预签名下载链接)
Nano->>Nano: 校验身份 + 存档有效性
Nano-->>App: 返回预签名 GET URL(60 秒有效)
App->>S3: GET 预签名 URL
S3-->>App: 存档文件(不经过 Notanote 服务器)设计说明
存档文件直接从对象存储节点传输到你的服务端,不经过 Notanote 服务器中转。这既降低了 Notanote 的带宽压力,也提高了下载速度。预签名 URL 有效期仅 60 秒,获取后请立即下载。
接口定义
1. POST /third-party/save/get — 获取存档元信息
查询指定玩家是否有存档、存档的最后更新时间和来源设备信息。建议在调用 pull 之前先调用本接口,确认存档存在以避免不必要的错误。
接口地址:POST https://api.notanote.cn/third-party/save/get
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
Name | string | 是 | 玩家的 Notanote 用户名(来自回调) |
Token | string | 是 | WebAuth 获取的 access_token |
TID | number | 是 | 你的第三方应用 ID |
SecretKey | string | 是 | 你的第三方应用密钥 |
请求示例
json
{
"Name": "player1",
"TID": 1001,
"SecretKey": "your-secret-key",
"Token": "access-token-from-callback"
}成功响应
json
{
"Status": true,
"Response": {
"Identifier": "nano.api.v2.third-party.save.get.succeed",
"Data": {
"Save": true,
"Time": 1710000000,
"Device": "iPhone15,3"
}
}
}| 字段 | 类型 | 说明 |
|---|---|---|
Save | boolean | 是否有存档(true / false) |
Time | number | 存档最后更新时间(Unix 时间戳,秒) |
Device | string | 存档来源设备型号 |
错误响应
| Identifier | 说明 | 处理建议 |
|---|---|---|
nano.api.v2.third-party.save.failed.saveNotInitialized | 该玩家尚未创建存档 | 提示玩家先在 Notanote 中创建存档 |
nano.api.v2.third-party.save.pull.failed.accessDenied | 玩家未开放第三方访问 | 引导玩家重新完成授权 |
nano.api.v2.webauth.get-session.failed.TIDVerifyFailed | TID 或 SecretKey 错误 | 检查凭证是否正确 |
2. POST /third-party/save/pull — 拉取存档
获取存档文件的临时下载链接。拿到 URL 后需在 60 秒内完成下载,过期需重新调用本接口。
接口地址:POST https://api.notanote.cn/third-party/save/pull
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
Name | string | 是 | 玩家的 Notanote 用户名 |
Token | string | 是 | WebAuth 获取的 access_token |
TID | number | 是 | 你的第三方应用 ID |
SecretKey | string | 是 | 你的第三方应用密钥 |
请求示例
json
{
"Name": "player1",
"TID": 1001,
"SecretKey": "your-secret-key",
"Token": "access-token-from-callback"
}成功响应
json
{
"Status": true,
"Response": {
"Identifier": "nano.api.v2.third-party.save.pull.succeed",
"Data": {
"Url": "https://s3.example.com/presigned/...",
"ExpireIn": 60,
"Method": "GET"
}
}
}| 字段 | 类型 | 说明 |
|---|---|---|
Url | string | 预签名下载地址,直接 GET 即可 |
ExpireIn | number | 链接有效期(秒),固定为 60 |
Method | string | 固定为 GET |
错误响应
| Identifier | 说明 | 处理建议 |
|---|---|---|
nano.api.v2.third-party.save.pull.failed.canNotFindSave | 存档不存在 | 先调 get 确认存档是否存在 |
nano.api.v2.third-party.save.pull.failed.accessDenied | 访问被拒绝 | 检查 Token 是否有效、玩家是否授权 |
完整调用示例
以下示例展示如何完整地拉取玩家存档文件。
js
async function downloadPlayerSave(playerName, accessToken) {
// 1. 查询存档元信息
const meta = await callApi('/third-party/save/get', {
Name: playerName,
TID: CONFIG.TID,
SecretKey: CONFIG.SECRET_KEY,
Token: accessToken,
});
if (!meta.Response.Data.Save) {
throw new Error('玩家尚无存档');
}
console.log(`存档最后更新于 ${new Date(meta.Response.Data.Time * 1000).toISOString()}`);
console.log(`存档来源设备:${meta.Response.Data.Device}`);
// 2. 拉取预签名下载链接
const pull = await callApi('/third-party/save/pull', {
Name: playerName,
TID: CONFIG.TID,
SecretKey: CONFIG.SECRET_KEY,
Token: accessToken,
});
// 3. 立即从对象存储节点下载存档文件(60 秒内必须完成)
const fileRes = await fetch(pull.Response.Data.Url);
if (!fileRes.ok) {
throw new Error(`下载失败: HTTP ${fileRes.status}`);
}
// 4. 处理存档文件
const buffer = await fileRes.arrayBuffer();
return Buffer.from(buffer);
}注意事项
预签名 URL 时效性
预签名 URL 有效期仅 60 秒。你的服务端获取后应:
- 立即发起下载请求,不要缓存 URL
- 下载失败时重新调用
pull获取新 URL,不要使用旧 URL 重试 - 避免将 URL 传递给前端或写入日志
SecretKey 仅限服务端
SecretKey 禁止写入:
- 前端代码
- 客户端配置
- 版本控制系统
- 客户端可读的 LocalStorage / Cookie
所有存档接口必须由你的服务端调用,禁止前端直接调用 Notanote API。
先查后拉
调用 pull 之前建议先调用 get:
- 确认存档存在,避免触发
canNotFindSave错误 - 获取存档最后更新时间,用于你的应用做版本判断
- 提前发现授权异常的情况
错误处理建议
| 错误类型 | 处理方式 |
|---|---|
accessDenied | 引导玩家重新完成授权 |
canNotFindSave | 提示玩家先在 Notanote 中创建存档 |
TIDVerifyFailed | 检查 TID 和 SecretKey 是否正确 |