Skip to content

第三方存档读取 ​

第三方应用在玩家授权后可以读取该玩家的存档数据。读取流程分为两步:

  1. 调用 get 查询存档元信息(是否存在、最后更新时间、来源设备)
  2. 调用 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

请求参数 ​

字段类型必填说明
Namestring是玩家的 Notanote 用户名(来自回调)
Tokenstring是WebAuth 获取的 access_token
TIDnumber是你的第三方应用 ID
SecretKeystring是你的第三方应用密钥

请求示例 ​

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"
    }
  }
}
字段类型说明
Saveboolean是否有存档(true / false)
Timenumber存档最后更新时间(Unix 时间戳,秒)
Devicestring存档来源设备型号

错误响应 ​

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.TIDVerifyFailedTID 或 SecretKey 错误检查凭证是否正确

2. POST /third-party/save/pull — 拉取存档 ​

获取存档文件的临时下载链接。拿到 URL 后需在 60 秒内完成下载,过期需重新调用本接口。

接口地址:POST https://api.notanote.cn/third-party/save/pull

请求参数 ​

字段类型必填说明
Namestring是玩家的 Notanote 用户名
Tokenstring是WebAuth 获取的 access_token
TIDnumber是你的第三方应用 ID
SecretKeystring是你的第三方应用密钥

请求示例 ​

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"
    }
  }
}
字段类型说明
Urlstring预签名下载地址,直接 GET 即可
ExpireInnumber链接有效期(秒),固定为 60
Methodstring固定为 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 是否正确