蓝奏云私有存储接口与通用直链解析:免登录下载、上传和每日验证

这个项目现在提供两种入口。日常下载使用免登录的蓝奏分享下载工具:输入分享链接和提取码,点击下载,自动提取临时 CDN 直链并开始下载。它不要求下载者登录站主的 GitHub 或 Cloudflare Access。

账号上传、文件列表和带历史哈希的私有恢复下载继续保留授权。本文同时记录通用分享解析与“蓝奏云私有存储接口”的实现、区别和每日验证。完整调用方法在免费静态接口文档;协议观察及验证日期为 2026 年 10 月 25 日。

1. 通用分享解析:输入链接和提取码即可下载

公开接口是 POST https://item.bismih520.com/public/api/resolve,请求 JSON 中只需要分享链接 url 和可选提取码 password,不携带 Service Token。示例中的链接需替换成实际分享:

curl --fail-with-body --max-time 80 \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.lanzouv.com/ishare","password":"abcd"}' \
  https://item.bismih520.com/public/api/resolve

成功响应含 name、direct_url、size、resolved_at 与 requires_login: false。客户端直接 GET 这个临时 CDN 地址,不再操作蓝奏分享页。网页工具自动发起下载,并提供再次下载和复制直链;也支持粘贴包含提取码的分享文字。

这里的解析器没有账号客户端、站主凭据或持久化 Cookie,每次请求使用新的匿名会话,只依据用户提交的分享信息访问第一方页面。解析到文件响应头后立即关闭探测连接,不把整个文件先下载到 VPS。v1.3 在这些独立匿名 Cookie 会话之间复用有界 TCP/TLS 连接池,不复用用户 Cookie。文件内容从蓝奏 CDN 直接到下载者,这与下面的私有校验下载是两种交付方式。

Cloudflare 仅对 item.bismih520.com/public/* 建立独立的公开路径策略,后端也只允许下载页、两份静态资源和公开解析 POST 匿名访问。Item 管理、账号列表、上传和旧私有下载没有因此公开。请求体最多 4 KiB,单 IP 每分钟 6 次、全站每分钟 30 次,同时最多 2 个解析;链接和提取码不落盘,服务关闭访问日志。

当前支持常见 lanzou*.com 域名的单文件分享,目录与其他蓝奏产品不在范围内。需要而未填提取码返回 400,提取码错误返回 403;无效链接、限流、人工验证、超时或协议变化会明确失败。短暂连接失败最多重试一次,并受总解析时限约束,不猜测密码,也不承诺永远免人工验证码。

真实验收使用专门创建的 4,270 字节 ZIP 分享:匿名解析成功,再从本机独立网络会话直接访问 CDN,无账号 Cookie、Referer 或服务凭据,HTTP 200 且完整 SHA-256 一致。还验证了缺少和错误提取码,以及管理与账号接口仍会进入 Access 登录。

通用直链下载的是蓝奏云上文件的原样内容。旧私有上传接口保存的 ZIP 容器,通过通用直链下载仍然是 ZIP;只有私有恢复接口会解出原始 payload。不要把“提取直链”误认为对任意分享都做了原始内容还原或病毒扫描。

2. 先确定“免密码下载”和“直链”的含义

下文私有存储模式的“免密码”,指下载者无需输入蓝奏云分享密码。网关使用账号权限读取自己文件的分享信息,在服务端提交所需密码。浏览器访问仍需要通过 Zero Trust 的身份检查,机器调用使用这个应用专用的 Service Token。拿到文件编号或限时链接,并不意味着可以绕过身份授权。

私有恢复下载与上面的 CDN 直链需要区分。蓝奏云的最终 CDN 地址通常有时效,获取过程中还可能经过中转页。网关对外给出自己的 HTTPS 地址,在服务器上取回并验证内容后直接返回附件。客户端收到的是原文件字节,不需要继续操作网页,也不依赖某一条临时 CDN 地址长期有效。

已授权浏览器 / 机器客户端
        │ HTTPS + Access 身份
        ▼
Cloudflare Access → Caddy → FastAPI 网关
                              │
                       蓝奏云账号接口
                              │
                       分享信息与下载参数
                              │
                       文件 CDN → 校验 → 原文件附件

完整性校验可以发现内容损坏或与上传记录不一致;它不等同于病毒扫描,也不代表原文件本身一定安全。

3. 和 GitHub 常见蓝奏云接口有什么区别

先说共同点:服务端代为读取分享页、提交密码、解析最终下载地址,并不是这个项目独有的能力。zaxtyson/LanZouCloud-API 已经提供账号操作、上传下载和获取直链等功能。没有对这些项目逐一做当前协议实测,不能仅凭仓库年龄就认定它们已经失效;本项目也没有使用一种能够永久避免上游变化的特殊接口。

方案主要定位与这个项目的关系
LanZouCloud-API 等库在程序中调用账号、文件及直链功能能力有重叠;集成方仍需根据自己的使用场景安排 HTTP 服务、权限和维护
OpenList 蓝奏驱动把网盘接入统一文件列表和多存储系统更适合文件管理门户;本文是只服务个人账号上传下载的小网关
通用分享解析链接加提取码,返回临时 direct_url匿名使用,文件由 CDN 直接交付;没有额外账号权限
私有账号接口上传后返回自己的 download_url,GET 收到恢复后的原文件ZIP 恢复、历史哈希、Access 和每日读写;文件经过自己的服务器

通用解析的流程是分享链接+提取码 → direct_url → CDN 下载。账号存储的流程则是 POST 上传 → download_url → 已授权客户端下载。前者省去分享页操作,后者额外恢复并验证私有容器。它们使用不同入口、权限和传输方式,不能混为一个“所有下载都要登录”的接口。

OpenList 的蓝奏云驱动文档介绍了账号、Cookie 和分享链接三种接入方式,也明确提醒这套历史逆向接口不会得到持续维护。对私人存储而言,账号方式比较合适,因为能够访问自己的文件,并在会话过期时重新登录。

但文档只能提供入口,不能替代实际验证。这次观察到,分享页的参数提交地址包含 apifile.woozooo.com,部分页面使用 iframe,部分新版参数放在 /fn 页面中。下载中转页还会相对请求 ajax.php。如果当前 URL 是 /file/,相对地址应解析为 /file/ajax.php;写成根路径 /ajax.php 就会得到错误结果。

本项目针对自己的账号与部署完成了真实上传和下载验证。因此实现没有把“正则能匹配到一个链接”当作成功。它必须最终拿到文件内容,并与上传时的哈希对应。域名、页面结构或签名字段变化时,应当明确报告协议不兼容,保留更新驱动的线索。

4. 账号接口:登录、会话刷新和上传前检查

网关把账号请求集中在一个独立客户端中,使用当前观察到的登录和文件管理接口。主要操作可以概括为:

操作作用处理原则
账号登录取得账号会话 Cookie凭据只保存在服务器私有配置中
目录和文件列表确认会话、获取自己的文件会话过期后重新登录,再执行读取
上传写入专用存储目录先用只读请求检查会话,再提交一次写入
分享信息取得文件分享标识及密码在服务端使用,不把账号 Cookie 交给下载客户端

上传前的会话检查很重要。只在服务启动时登录,会出现“刚部署可以上传,过几天直接上传失败”的情况。先用一个轻量只读请求检查会话,能够在真正写入之前完成续期,也避免把重复上传当成会话探测。

读取发生短暂连接故障时可以进行一次有上限的重试;上传结果不明确时则不能直接重发。远端可能已经接收了文件,只是响应没有到达。盲目重试会制造重复文件,后续也很难判断哪个编号才是本次写入。

5. 用一个普通 ZIP 容器保存任意格式

不同扩展名可能受到网盘上传规则影响。这个接口把原文件封装成一个普通 ZIP,再交给上游保存。ZIP 中只允许两个固定条目:

item-<随机编号>.zip
├── manifest.json
└── payload

payload 是原始字节;manifest.json 保存容器格式标识、原文件名、长度和 SHA-256。上传时还会计算整个 ZIP 的 SHA-256,并把这些信息与云端文件编号一起存入本地 SQLite。

{
  "format": "item-storage-v1",
  "name": "example.bin",
  "size": 4096,
  "sha256": "原文件的 SHA-256"
}

固定条目名让恢复过程更容易约束。下载时不会执行通用的 extractall(),只读取预期的清单和 payload,复制到服务器生成的临时路径。文件名来自清单记录,经过清理后用于附件响应,不作为归档解压路径。

目前单次上传限制是 95 MiB,给 ZIP、表单及上游限制留出空间。容器没有额外加密;它解决格式、恢复和完整性问题,存储内容的保密性仍需要账号、分享设置和访问控制共同承担。

6. 上传成功要经过一次真正的云端回读

上游返回文件编号,只能证明它声称接收了上传。网关还会按这个编号重新取得文件,校验容器哈希、清单、原始长度和原文件哈希。

  1. 接收原文件,计算长度和 SHA-256。
  2. 生成 ZIP 容器,计算容器 SHA-256。
  3. 上传并保存云端文件编号,先持久化本地元数据。
  4. 从云端重新下载这个文件,验证整个 ZIP。
  5. 读取固定条目并还原原文件,确认原始字节一致。

所以接口把两个结果分开:HTTP 201 表示上传和回读都验证成功;HTTP 202 表示云端已经接收,但本次回读暂时没有通过。202 会返回文件编号、校验状态和错误码,调用方应按编号继续检查下载,避免重新上传一份。

7. 下载解析与验证页面的边界

下载客户端与账号客户端使用独立会话。前者只访问分享页、参数接口和经过检查的下载地址,不会把账号 Cookie 带到文件 CDN。

对于当前页面出现的固定 JavaScript Cookie,网关只提取已知格式的参数并计算对应值;对于当前的自动验证表单,则按已经观察到的字段提交请求。它不执行网页中的任意 JavaScript,不安装第三方下载器,也不把中转 HTML 发给用户当作文件。

这些自动流程不能推出“以后永远不需要验证码”。上游若改成人工验证码、拒绝请求、限流或改变协议,网关会返回明确失败。它不会用无限重试、切换账号或伪装一个成功结果来掩盖问题。

每次跳转都检查 HTTPS、域名白名单和 DNS 解析结果,拒绝私网、回环地址、携带账号密码的 URL 及不允许的端口。当前实测的下载链路包括蓝奏云相关中转域名与 webgetstore.com 文件存储域名;以后出现新域名,需要先确认来源,再更新白名单。

8. 把原文件作为附件返回

新上传文件在服务器上完整取回并验证后,网关才开始向客户端发送内容。这会使用自己的服务器带宽与临时磁盘,也会推迟首字节返回;“直接下载”描述的是省去分享页操作,不代表没有等待。还原结果使用 application/octet-stream、Content-Disposition: attachment 和 X-Content-Type-Options: nosniff,同时返回 X-Content-SHA256,让命令行客户端能够再核对一次。

下载支持 HTTP Range,但为了保持对云端副本的完整验证,当前实现仍先完成一次取回和校验,再从本地临时文件返回所需片段。这适合私人小文件存储;频繁读取大文件时,需要进一步考虑经过验证的缓存及容量策略。

临时文件的生命周期也包含异常路径。正常发送结束、客户端断开或响应异常后,都要释放临时目录和传输并发名额;服务器重启时,还会清理超过保留时间的本项目旧临时目录。

9. Zero Trust:管理与账号接口需要授权

私有管理浏览器使用 GitHub 身份登录,账号接口的机器客户端使用专用 Service Token。源站服务只监听本机回环地址,Caddy 对外入口限制 Cloudflare 来源;后端进一步验证 Access JWT 的签名、签发者、应用受众和有效期,而不是仅仅信任一个请求头。

Cloudflare 的 JWT 验证文档说明了源站验证的基本方式。这里使用对应团队的公开 JWK 获取验签公钥,校验通过后才处理应用请求。

账号密码、Cookie、签名密钥与机器凭据都不放进网页、文章或 Git 仓库。客户端拒绝自动跟随跳转,以免把专用认证请求头发送到其他域名。限时链接也继续受 Access 保护:它限制的是文件地址的可用时间,不能替代身份检查。

10. 接口怎么调用

在线接口文档和可下载的 OpenAPI 规格已经放到 Cloudflare Pages,公开可读,页面不请求正式 API,也不接收用户凭据。没有 Functions、数据库或外部脚本,查看说明不会消耗自己的 VPS 资源。旧文档入口仅保留跳转,实际文件操作仍需授权。

Cloudflare Pages 定价说明将不调用 Functions 的静态资源请求列为免费;这里仅部署预生成的 HTML、CSS 和 JSON。接口服务器的上传下载带宽、临时磁盘与云端回读开销并没有因此消失。公开解析使用上文的 /public/api/resolve;下面是私有账号接口路径:

方法路径作用
GET/api/v1/files列出默认存储目录
POST/api/v1/filesmultipart 字段 file 上传
GET/api/v1/files/{id}/download下载原文件
POST/api/v1/files/{id}/link生成限时签名链接
GET/api/v1/projects项目条目与动态验证状态

下面是私有上传示例,只使用环境变量占位符,不包含真实凭据:

curl --fail-with-body \
  -H "CF-Access-Client-Id: ${CF_ACCESS_CLIENT_ID}" \
  -H "CF-Access-Client-Secret: ${CF_ACCESS_CLIENT_SECRET}" \
  -F "file=@example.bin" \
  https://item.bismih520.com/api/v1/files

上传响应中已经带有 download_url,不需要调用者处理蓝奏分享密码:

{
  "id": "123456789",
  "name": "example.bin",
  "verified": true,
  "download_url": "https://item.bismih520.com/api/v1/files/123456789/download"
}

上面省略了长度和哈希字段,编号仅作示例。已登录浏览器直接打开返回的地址即可;脚本则携带相同的 Access 请求头 GET 该地址。下载是原文件附件,既不展示分享页,也不要求再点按钮。它不等于任何匿名访客都能下载,限时链接同样保留身份验证。

仓库中的命令行客户端提供 list、upload、download 和 link。下载先写入临时文件,只有本地计算的 SHA-256 与响应头一致,才正式生成目标文件,防止把半截下载当成完整结果。

11. 每天验证:为什么不能只检查 HTTP 200

一个页面能打开,不能证明账号还可以登录、文件还能上传,或者下载参数仍然有效。服务器因此使用独立的 systemd timer,每天北京时间 08:00 运行真实验证,补跑关机期间错过的任务。这个检查在服务器上完成,不依赖我的电脑或 Codex 聊天保持在线。

  1. 处理上一次尚未完成的测试文件清理。
  2. 确认匿名访问仍会进入 Cloudflare Access。
  3. 用专用机器身份访问正式域名,读取服务存活信息与账号文件列表。
  4. 生成带随机内容的小测试文件,经正式上传接口提交,并要求云端回读通过。
  5. 下载原文件,核对内容、SHA-256 和附件响应头。
  6. 检查 Range 分段下载,以及限时链接能够下载、修改签名会被拒绝。
  7. 匿名提交测试文件的分享链接和提取码,取得直链后从 CDN 下载,核对实际云端 ZIP 的 SHA-256。
  8. 把本次测试文件移入蓝奏云回收站,确认它从存储目录消失,再删除对应测试元数据。
  9. 独立访问本文,确认公开页面和正文仍然可以读取。

清理只允许处理随机测试前缀、原始哈希和本地元数据共同匹配的对象。任何正常用户文件都不在清理范围内。如果上传结果不明确,检查程序会保存意图;如果无法确认或清理,会报告失败,并停止继续创建新的测试上传,避免每天堆积垃圾。

验证结果写入私有数据目录的 JSON,采用临时文件和原子替换,保留最近 90 次结果。任务有执行时限和内存上限;异常退出时补写失败状态。页面展示的是最近一次实际验证结果与时间,而不是实时承诺。

12. 在项目列表里读懂 🟢 和 🔴

Item 现在仅保留蓝奏云存储接口这一行,紧凑展示项目名称、简介、GitHub/静态文档和接口状态。博文与论文不再占用项目条目。状态灯显示的是蓝奏接口最近一次真实上传下载验证,v1.2 起也覆盖公开分享解析与 CDN 下载;后台仍独立检查本文可读性,结果不混入接口的绿灯判断。

显示含义后续动作
🟢 可用最近一次对应范围的验证全部通过查看检查时间,按需使用
🔴 需检查接口、完整性、授权、链接或测试清理有步骤失败查看失败说明和服务器任务日志
🔴 检查超时超过 36 小时没有有效结果,或检查任务长时间未完成先确认定时器、主机和凭据状态
⚪ 待验证 / 正在验证尚无首轮结果,或当前检查正在执行等待结果;长时间未完成会转为红色

尤其要处理“定时器停了,但上次结果还是成功”的情况。页面会按照结果时间重新计算是否过期,不会无限沿用一个旧的绿灯。

13. 红灯之后怎么排查

先从失败所在的层次缩小范围。机器身份失效时,应检查 Access 的 Service Token 与应用策略;账号列表失败时,检查蓝奏云会话和上游可用性;上传已接收但回读失败时,先按已有编号重试验证,避免重复上传。

出现哈希不匹配时,继续阻止文件交付,保留已有元数据排查;出现协议变更或新下载域名时,重新观察第一方页面和网络行为,更新解析及白名单后再执行完整回归。真正的人工验证码、平台限流和网络故障也会使检查失败,它们不一定都代表代码有缺陷,但都值得在维护页面上被看见。

systemctl status item-storage-monitor.timer
journalctl -u item-storage-monitor.service -n 50 --no-pager
systemctl start item-storage-monitor.service

最后一条命令会手动执行一轮同样的验证。它需要在部署服务器上由有权限的维护者操作,网页访客不能随意触发测试写入。

14. 这次验证了什么,还有哪些限制

首版已经完成真实 1 MiB 二进制、中文文件名、空文件、Range、限时链接和命令行下载验证,上传与下载的原始 SHA-256 一致。持续自检是在这些流程上增加服务器调度、状态过期判断、异常退出处理和测试对象回收。

加入持续自检时,相关隔离测试累计通过 42 项。服务器的首轮检查确实产生过一次红灯:小测试文件的上传及云端回读约用了 95 秒,原检查器等待 90 秒便超时。把这一步等待调整到 110 秒后,重新执行的完整检查全部通过,测试文件也已回收;失败与成功两次结果都保留在历史中。此次检查进程的内存峰值约为 40 MiB。这也说明,小文件同样可能受到网络和上游验证延迟影响,不能仅按文件大小估计响应时间。

目前没有进行 95 MiB 极限压力测试。较大文件依然会受到上游吞吐量、服务器容量和 Cloudflare 请求超时影响;高频大文件访问也需要独立的缓存及存储设计。依赖漏洞审计反映的是检查时的已知数据库结果,后续仍应定期更新依赖。

这个项目的维护入口因此不只是一篇部署教程:正式接口、验证记录、状态时间和故障日志要能连起来。下次审查项目目录时,能够直接知道哪些流程最近通过、哪些项目需要检查,以及绿灯到底验证到了哪一步。

v1.2 新增的匿名入口、私有路由隔离、提取码错误、请求体上限、限流、匿名会话隔离、只探测响应头和短暂故障重试等回归检查,与原有检查合计 62 项通过。通用分享下载采用临时 CDN 地址,因此不消耗 VPS 的完整文件代理带宽,但解析仍受第一方页面协议和下载节点可用性影响。

15. 用五个外部分享检验通用解析

这次额外找了五个公开单文件分享:三个无提取码的 ZIP/7z 测试与页面包,以及两个带提取码的软件压缩包,大小从 1,442 字节到约 2.08 MB。最终均经正式匿名接口提取地址,再从本机直接完整下载,HTTP 状态、长度与压缩包文件头符合预期,并记录 SHA-256。仅检查传输,不保存、解压或执行内容,也不把第三方软件分享当作官方下载推荐。

外部样本暴露了文件名问题:部分无密码页没有返回 inf,还有 CDN 普通 filename 头使用百分号编码。现在从文件名头或 fn 参数恢复名称,正确处理中文和一次解码,清理路径与控制字符。

更关键的是,两份旧 ZIP 的 CDN 地址已经取得,但 VPS 访问最终节点会超时,本机却能下载。通用解析的目标是把直链交给客户端,不应要求站主服务器先能访问每一个文件节点。因此,第一方已经签发、包含 fn 的已知 webgetstore 文件直链现在直接返回;未探测时 size 为 null。下载客户端再实际连接节点,这次五个样本都完成了下载。部分旧中转仍需响应头区分,HTTPS、域名和公网 DNS 检查保持有效。

v1.2.1 的隔离回归共 63 项通过。最初失败与修正后的结果都保留,不能用最终五个成功样本推断所有分享或所有网络永远可用。

16. 提速和并发:减少重复访问,保持上游负担有界

v1.3 保留原下载页与 POST /public/api/resolve 地址,以及已有 JSON 返回字段。主要优化来自短时复用和请求合并。不能靠跳过验证等待、增加重试、轮换 IP 或定期刷分享来换取表面速度。

成功结果只在当前服务进程的内存中有效 20 秒,最多 128 条;命中不续期。缓存键使用进程随机密钥,对客户端 IP、规范化分享链接和实际提取码计算 HMAC,不保留这些原文。结果包含文件名与临时 CDN 票据,服务重启即清空,不进入 Cloudflare 或浏览器共享缓存。不同 IP、不同提取码和缺少提取码分别处理,失败不缓存。票据失效时可提交可选的 refresh:true 跳过缓存;刷新失败也不会回退旧结果。

正在解析的相同请求共用一项工作,最多 32 个等待者。实际向上游解析的工作线程仍只有 2 个,另保留 6 个等待位置,最多排队 12 秒。最初的 8 秒等待小于这次正常解析所需时间,因此按测量结果调整为 12 秒,容纳一轮正常工作。等待超时或已无调用者的队列项在轮到它时直接丢弃,不再访问蓝奏。客户端断开不会让仍在运行的解析提前释放工作名额;失效队列项也仍计入容量,直到线程实际取走,防止取消请求制造隐藏队列。

每次解析仍拥有新的匿名 Session 和 Cookie 容器,仅通过共享的有界适配器复用 TCP/TLS 连接。会话关闭不关闭其他线程正在使用的连接池,整个服务退出后才释放连接池;HTTP 错误和读取异常同样关闭响应,避免连接名额泄漏。HTTPS、提供方域名、公网 DNS 及自动验证等待保持有效。上游返回限流时,新解析全局冷却 30 秒,排队工作同样遵守;已有有效缓存仍可使用。没有后台预热或刷新分享,空闲时不会因为缓存机制反复访问提供方。

验证结果
正式接口:3 个相同请求同时提交1 次新上游解析,2 次合并;客户端各约 9.67 秒
随后 3 个相同请求同时提交均命中缓存,客户端中位数 267 毫秒;应用处理 0.1–0.3 毫秒,新增上游解析 0 次
取得的直链实际下载2,083,029 字节,HTTP 200,SHA-256 与之前记录一致;不保存或执行内容
离线模拟 20 个相同请求只执行 1 次模拟解析;不向蓝奏发送压力流量
离线模拟 8 个不同请求上游工作并发峰值 2,按队列依次完成

正式验证共提交六次匿名解析请求,保持每 IP 每分钟六次、全站三十次的原有限制。一个旧版同样本的解析约为 10.45 秒,新版首次约为 9.67 秒;这两次不足以证明首次延迟稳定下降。另一个基线分享页曾连接超时,仍如实记录。缓存命中明显降低重复解析等待,首次解析继续受网络及上游验证影响,也不能把 20 秒缓存有效期理解为对 CDN 票据寿命的保证。

新增的缓存、提取码隔离、队列容量、取消请求、冷却、连接池与错误释放等检查,使隔离测试累计 78 项通过。受 Access 保护的健康接口仅返回聚合调度计数与配置,不包含用户链接、提取码、IP 或直链。生产继续运行单个 Uvicorn worker;未来扩展多个进程或副本时,必须先使用统一限流和调度,不能直接倍增进程内额度。实现与可重复执行的离线基准已放入私有仓库,免费静态接口文档也同步说明 refresh 参数和耗时响应头。

上一篇