Skip to content

Practice Data

ChangYo edited this page Oct 26, 2026 · 3 revisions

文件、时间与缓存

这页把校园工具里最容易出错的三个通用问题抽出来:文件怎么下、时间怎么算、缓存怎么不骗人。平台特有的细节放各平台页。

相关:Canvas、Mail、Classroom-Video、交大云盘。

1. 文件下载

三种常见链路

类型 例子 关键点
直接返回文件流 邮箱附件、Pan 流式写盘,别整包读内存
302 到对象存储 Canvas 文件 第一段带 Token,第二段不带;签名 URL 是凭据
签名直链 课堂视频 MP4 免 Cookie、支持 Range、会过期;每次现取

通用规则

  • 先拿元数据(大小、MIME、文件名),再下载。
  • 下载到临时文件,校验后 rename;失败清理。
  • 校验大小;有条件校验 hash。
  • 大文件流式写;不要 arrayBuffer() 整个 1GB。
  • 并发限速;429/403 退避。
  • 文件名:过滤 <>:"/\|?*、控制字符、Windows 保留名;限制长度;防路径穿越。
  • 同名冲突:跳过/覆盖/加序号,策略要明确。
  • 断点续传:Range + If-Range;服务端不支持就重下。
  • 签名 URL 不落日志、不存库、不发模型。

错误处理

情况 处理
302 缺失 Location 报错;不要猜
重定向到非预期域 拒绝;防 SSRF/钓鱼
403(对象存储) 签名过期/权限错;重新取签名,不要重试旧 URL
416 Range 越界;检查文件大小
200 但大小不符 截断/代理错误;重试
429 退避;读 Retry-After

2. 时间

三种格式

格式 来源 注意
Unix 秒 Open API、InfoPlus、数据资源 API 单位为秒,不是毫秒
Unix 毫秒 课堂视频转写 bg/ed 除 1000 得秒
ISO 8601 Canvas due_at、邮件日期 带 Z 就是 UTC

时区

  • 校园业务默认 Asia/Shanghai。
  • 服务器返回的 Z 时间是 UTC;展示时转本地。
  • 计算「第 N 周」时,先把学期开始日归一到周一,再按本地日历算;不要用 UTC 日期直接加。
  • 中国没有夏令时,但不要假设所有用户都在 +8;如果做跨时区,显式带 TZID。

学期与周次

  • 学期代码各平台不同:i.sjtu 用 xnm + xqm=3/12/16;Open API 用 2026-2027-1。
  • 周次表达式可能是中文(1-16周(单));解析后展开成具体周。
  • 没有学期开始日期时,不要生成具体日期;显示「第 N 周」或让用户手填。
  • DDL 用 due_at 的 UTC 时刻;不要二次加减 8 小时。

3. 缓存与增量

先问三个问题

  1. 这个接口有稳定的变更游标吗?
  2. 没有游标时,用什么字段判断变化?
  3. 同步失败/返回空时,缓存该保留还是清空?

常见模式

平台 增量依据 注意
Canvas updated_at、文件 id 没有稳定 change cursor;定期全量校核
邮箱 UIDVALIDITY + UID UIDVALIDITY 变了必须清空重同步
水源 last_posted_at、more_topics_url 没有 change cursor;按页对比
课堂视频 场次 id + 状态字段 转写/PPT 异步;未就绪下次重拉
教务 学期 + 课程 id 全量替换该学期;失败保留旧数据

原则

  • 失败不清空:网络错误、空响应、解析失败都保留旧缓存,标错误。
  • 区分「删除」与「没拿到」:只有服务端明确返回「不存在/已删除」才删本地。
  • 墓碑:需要删除同步时,记录 tombstone,不要靠「本次没返回」推断删除。
  • TTL:结构/分类等低频数据可以缓存几分钟;个人数据不要缓存太久。
  • 可重建:缓存应能从源重建;不要把唯一副本放缓存。
  • 迁移:缓存 key 加版本;结构变了就重建,不要读旧格式。

列表字段可能不全

列表接口为了体积会裁字段,不能把列表项当详情:

  • 选课社区列表的 rating.distribution 恒为 [0,0,0,0,0],详情才有真实分布。
  • 第二课堂列表没有 in_signed_up,报名状态只在详情。
  • 传承的班级端点 materials 恒为 null,资料要走 /material。

[实测 2026-10-26]

4. HTML 与富文本

来源:

  • Canvas 作业 description、页面 body、讨论 message。
  • 水源 cooked(服务端消毒过,但仍要清洗)。
  • 邮件 text/html。
  • 教务/新闻网页。

处理:

  • 用白名单 sanitizer;去掉 <script>、事件属性、javascript: URL、iframe(除非明确需要)。
  • 相对链接补全 base;图片走代理/鉴权,不要直连外域。
  • 邮件远程图片默认不加载(跟踪像素)。
  • 代码块/数学公式按需渲染;不要执行任意 HTML。
  • 保留原文链接,方便核对。

5. ID 与主键

类型 例子 注意
数字 id Canvas course/file/assignment 稳定;但跨实例可能冲突
GUID Open API/InfoPlus 字符串;不要转数字
bsid/code 教学班/课程 可能带学期/班号;不要当全局唯一
jxb_id i.sjtu 教学班 课表主键候选
teclId 课堂视频教学班 与课程代码映射
activity_id 第二课堂热门列表 与普通列表的 id 不同名
base64 第二课堂详情页 URL 不是接口 id,需解码或换成数字 id
UID IMAP 只在同一 UIDVALIDITY 内稳定
topic_id/post_id 水源 数字;topic 是核心实体

原则:用服务端提供的稳定 id,不要用显示名/标题做键。显示名会改,标题会重名。

同一个实体在不同接口里可能换主键名:第二课堂列表用 id,热门用 activity_id,网页 URL 又用 base64。解析前先确认当前端点的键名,不要写一个通用 getId()。[实测 2026-10-26]

6. 检查清单

  • 下载链路区分了「带 Token 的第一段」和「不带 Token 的第二段」。
  • 文件名安全,冲突策略明确。
  • 大文件流式,内存有上限。
  • 时间格式(秒/毫秒/ISO)明确,时区明确。
  • 周次/学期开始缺失时有降级。
  • 同步失败不清空缓存。
  • UIDVALIDITY/updated_at 等游标用对。
  • HTML 清洗,远程资源不默认加载。
  • ID 稳定,不用标题做键。

7. 证据

  • Canvas 302/S3/大小/分页:[实测 2026-09-10]
  • 邮箱 UIDVALIDITY/窗口:[实测 2026-09,Dela mail]
  • 课堂视频签名/Range/异步:[实测 2026-10-06]
  • 水源 cooked/分页/标签:[实测 2026-09-15]
  • 节次/周次:[实测 2026-09,Dela schedule]
  • 列表裁剪字段、第二课堂主键名:[实测 2026-10-26]

变更记录

  • 2026-10-25:首版。抽取文件、时间、缓存、HTML、ID 的通用规则。
  • 2026-10-26:补「列表字段可能不全」与第二课堂主键差异。

Clone this wiki locally