本文基于一个完整的 Node.js demo,系统讲解如何通过百度网盘开放平台 OAuth 授权,实现摄影公司将客户照片上传到客户自己的百度网盘,解决存储成本持续上涨的问题。内容覆盖应用创建、OAuth 授权流程、Token 管理、目录操作、分片上传三段式、文件预览及生产环境补强方案,可作为百度网盘开放平台对接实操手册使用。
一、问题背景:图片太多,存储费吃不消
摄影行业有个很现实的问题:图片太多了。
一次婚礼、一次旅拍、一次商业拍摄,动辄几 GB、几十 GB。客户希望随时能看、能下载、能长期保存;公司如果全部放在自己的服务器或者 OSS 上,存储费、流量费、备份费都会持续上涨。
小明接到这个任务后,换了个思路:
客户本来就有自己的网盘,能不能让客户授权公司代管指定目录,公司只负责把照片上传到客户自己的网盘里?
这样一来,资料归客户自己所有,公司不用长期背负大规模存储成本;客户也能通过熟悉的百度网盘查看、下载和管理照片。
二、Demo 能力概览
当前项目是一个纯 Node.js demo,没有使用 Express。后端入口是server.js,前端页面放在public目录。
整体能力包括:
| 序号 | 能力 | 说明 |
|---|---|---|
| 1 | 创建业务用户 | 如"张三婚礼客户""李四写真客户" |
| 2 | 发起 OAuth 授权 | 为指定用户发起百度网盘 OAuth 授权 |
| 3 | 保存 Token | 授权回调后,保存 access_token、refresh_token、过期时间 |
| 4 | 查询网盘容量 | 检查客户网盘剩余空间 |
| 5 | 创建目录 | 在客户网盘中创建资料目录 |
| 6 | 列出文件 | 查询指定目录下的文件列表 |
| 7 | 上传文件 | 上传本地照片或视频到客户授权后的网盘目录 |
| 8 | 预览文件 | 对图片和视频做简单预览 |
从业务角度看,它模拟的是:摄影公司后台选择一个客户 → 让客户扫码授权百度网盘 → 公司后台把拍摄资料上传到客户自己的网盘目录。
三、整体架构
3.1 项目结构
网盘demo
├─ server.js # Node 后端,处理 OAuth、上传、目录、容量、预览
├─ public
│ ├─ index.html # 页面结构
│ ├─ app.js # 前端交互逻辑
│ └─ styles.css # 样式
├─ data
│ ├─ baidu-token.json # 本地保存用户和 token
│ ├─ oauth-states.json # OAuth state 防重放记录
│ ├─ oauth-callback.log # 授权回调日志
│ └─ uploads # 前端分片上传到后端后的临时分片目录
├─ .env.example # 百度开放平台配置示例
└─ package.json
3.2 技术链路
前端页面 → Node 后端 → 百度 OAuth 授权 → 百度网盘开放接口 → 客户自己的百度网盘
/apps/{应用名}/uploads
关键点:公司服务器只承担"中转"和"调用百度接口"的角色。真正落盘的位置,是客户授权后的百度网盘,不是公司的服务器长期保存。
四、第一步:百度开放平台创建应用
4.1 获取关键参数
到百度开放平台创建应用,拿到两个关键参数:
| 参数 | 说明 |
|---|---|
| API Key | 应用的客户端标识 |
| Secret Key | 应用的客户端密钥 |
4.2 环境变量配置
BAIDU_CLIENT_ID=你的 API Key BAIDU_CLIENT_SECRET=你的 Secret Key BAIDU_REDIRECT_URI=http://localhost:3000/oauth/callback BAIDU_APP_NAME=你的百度网盘应用名 PORT=3000⚠️ 注意:
BAIDU_REDIRECT_URI必须和百度开放平台后台配置的回调地址保持一致,否则授权完成后百度无法正确回传 code。
4.3 授权范围
| Scope | 用途 |
|---|---|
basic | 基础账号授权 |
netdisk | 访问百度网盘相关能力 |
五、第二步:创建客户用户
Demo 页面上有"创建用户"功能。在真实业务里,这个用户对应摄影公司的客户:
| 客户标识 | 客户名称 |
|---|---|
| 客户A | 王先生婚礼 |
| 客户B | 陈女士亲子照 |
| 客户C | 某品牌商业拍摄 |
后端接口:POST /api/users
后端会生成一个id,并把用户信息写入data/baidu-token.json:
{ "id": "用户ID", "name": "客户名称", "token": null, "created_at": "创建时间" }此时token还是空的——客户还没有授权百度网盘。
六、第三步:发起百度网盘授权
客户创建完成后,点击"授权百度网盘"。前端跳转到:
GET /oauth/start?userId=客户ID6.1 后端处理流程
| 步骤 | 操作 |
|---|---|
| 1 | 检查.env里的百度应用配置是否完整 |
| 2 | 根据userId找到当前客户 |
| 3 | 生成随机 nonce,把 userId 和 nonce 编码成 state |
| 4 | state 写入oauth-states.json,设 30 分钟有效期 |
| 5 | 拼接百度 OAuth 授权地址,302 重定向到百度授权页 |
6.2 授权地址关键参数
response_type=code client_id=BAIDU_CLIENT_ID redirect_uri=BAIDU_REDIRECT_URI scope=basic,netdisk state=后端生成的 state qrcode=1 force_login=1💡 state 不是摆设:① 知道这次授权该绑定到哪个客户;② 防止伪造回调和重复使用授权状态。
force_login=1则是让客户重新确认登录身份,避免浏览器已有账号影响授权。
七、第四步:客户扫码授权,百度回调系统
客户在百度页面完成授权后,百度回调:
GET /oauth/callback?code=授权码&state=授权状态7.1 后端回调处理
| 步骤 | 操作 |
|---|---|
| 1 | 解析并校验 state |
| 2 | 从oauth-states.json消费掉这条 state,防止重复使用 |
| 3 | 检查 state 是否过期 |
| 4 | 用 code 调用百度 token 接口换取 token |
7.2 换取 Token
https://openapi.baidu.com/oauth/2.0/token grant_type=authorization_code code=百度回传的授权码 client_id=BAIDU_CLIENT_ID client_secret=BAIDU_CLIENT_SECRET redirect_uri=BAIDU_REDIRECT_URI百度返回成功后,保存到本地:
{ "access_token": "...", "refresh_token": "...", "expires_in": 2592000, "expires_at": "绝对过期时间" }⚠️ 安全提醒:Demo 里 token 明文存文件,生产环境不要这样做,应该加密后存数据库或密钥系统。
7.3 自动创建目录
授权完成后,后端会自动尝试创建两个目录:
/apps/{BAIDU_APP_NAME} /apps/{BAIDU_APP_NAME}/uploads百度网盘开放平台通常限制应用只能操作/apps/应用名目录下的文件。这个限制反而适合业务隔离——公司只管理客户授权给这个应用的目录,不碰客户网盘里的其他私人文件。
八、第五步:查询客户网盘容量
前端调用:
GET /api/quota?userId=客户ID后端请求百度接口:
https://pan.baidu.com/api/quota?access_token=xxx&checkfree=1前端拿到total和used后计算:总容量、已使用、剩余容量、使用百分比。
💡 实践心得:上传前先看客户网盘是否还有足够空间,避免照片传到一半才失败。
九、第六步:创建客户资料目录
摄影客户的资料通常需要分组:
/apps/huanjing/uploads/王先生婚礼/原片 /apps/huanjing/uploads/王先生婚礼/精修 /apps/huanjing/uploads/王先生婚礼/视频9.1 接口与兜底
| 优先级 | 接口 | 说明 |
|---|---|---|
| 优先 | xpan/file?method=create | 百度网盘开放平台标准接口 |
| 兜底 | pcs/file?method=mkdir | PCS 接口兼容方案 |
💡 为什么要做接口兜底?百度不同接口、不同应用权限下的表现可能不完全一样。Demo 没有只押一个接口,而是做了兼容处理。
十、第七步:上传照片到客户自己的网盘
上传是整个 demo 的核心。
前端选择文件后,按 512KB 切片:
const chunkSize = 512 * 1024;每个分片提交给后端:
POST /api/upload-chunk?userId=客户ID&dir=目标目录&filename=文件名&uploadId=上传ID&index=分片序号&total=总分片数10.1 后端分片处理流程
| 步骤 | 操作 |
|---|---|
| 1 | 校验 uploadId,避免非法路径 |
| 2 | 读取分片内容,写入本地临时目录data/uploads/{uploadId}/{index}.part |
| 3 | 统计已收到的分片数,未收齐则返回进度 |
| 4 | 全部收齐后,按顺序合并成完整文件 |
| 5 | 调用百度网盘上传接口,完成后删除本地临时分片目录 |
⚠️ 当前限制:合并后会把文件读入内存,限制最大 100MB。生产化时应改成流式上传或更大粒度的服务端分片调度。
十一、第八步:百度网盘上传三段式
后端真正把文件传到百度网盘时,走的是典型的三段式:
11.1 precreate:预创建
先计算文件内容的 MD5,然后调用:
https://pan.baidu.com/rest/2.0/xpan/file?method=precreate参数:
| 参数 | 说明 |
|---|---|
path | 目标文件路径 |
size | 文件大小 |
isdir | 是否目录(0=文件) |
block_list | 文件 MD5 列表 |
返回结果:
| 返回值 | 含义 | 后续操作 |
|---|---|---|
return_type=2 | 命中秒传或已有文件 | 直接返回结果 |
uploadid | 需要继续上传 | 进入第二步 |
11.2 superfile2:上传分片内容
拿到uploadid后,调用:
https://d.pcs.baidu.com/rest/2.0/pcs/superfile2?method=upload&type=tmpfile&partseq=0Demo 里因为最终合并成一个 buffer,对百度来说只有一个上传分片,partseq是0。百度上传成功后返回该分片的 MD5。
11.3 create:创建文件
最后调用:
https://pan.baidu.com/rest/2.0/xpan/file?method=create参数:
| 参数 | 说明 |
|---|---|
path | 目标路径 |
size | 文件大小 |
isdir | 0(文件) |
rtype | 3(重命名策略) |
uploadid | 上一步拿到的 uploadid |
block_list | 文件 MD5 列表 |
这一步才是真正让文件出现在客户网盘目录里。
代码里还保留了上传兜底逻辑:如果开放平台上传接口不可用,会尝试 PCS 的file upload接口。
十二、第九步:查看目录和预览文件
12.1 列出文件
GET /api/files?userId=客户ID&dir=网盘目录后端调用:
https://pan.baidu.com/rest/2.0/xpan/file?method=list返回文件名、大小、修改时间。
12.2 文件预览
GET /api/preview?userId=客户ID&path=文件路径后端代理请求百度下载接口,把文件流转发给浏览器:
https://d.pcs.baidu.com/rest/2.0/pcs/file?method=download🔒 安全关键点:后端代理下载,不把 access_token 暴露给前端。前端永远不要直接持有长期有效的 access_token。
十三、接口清单一览
| 方法 | 接口 | 说明 |
|---|---|---|
| GET | /api/config | 获取配置 |
| POST | /api/users | 创建客户 |
| GET | /oauth/start | 发起授权 |
| GET | /oauth/callback | 授权回调 |
| GET | /api/quota | 查询容量 |
| GET | /api/files | 列出文件 |
| GET | /api/directories | 查询目录 |
| POST | /api/directories | 创建目录 |
| POST | /api/upload | 小文件直接上传 |
| POST | /api/upload-chunk | 分片上传 |
| GET | /api/preview | 文件预览 |
十四、业务流程总结
站在摄影公司的视角,整个流程如下:
| 步骤 | 操作 |
|---|---|
| 1 | 后台创建客户 |
| 2 | 给客户一个授权入口,或现场让客户扫码授权百度网盘 |
| 3 | 系统拿到客户授权 token |
| 4 | 系统自动创建应用目录和上传目录 |
| 5 | 工作人员选择客户和目录 |
| 6 | 上传照片、视频、精修图 |
| 7 | 文件进入客户自己的百度网盘 |
| 8 | 客户后续在百度网盘里自行查看、下载、长期保存 |
这个模式的核心不是"白嫖网盘",而是把存储责任回归给资料所有者。公司系统负责组织、上传、交付和体验;客户网盘负责长期保存。
十五、生产环境待补强能力
Demo 已经能跑通主链路,但要正式上线,还需要补强以下能力:
| 序号 | 能力 | 当前状态 | 生产要求 |
|---|---|---|---|
| ① | Token 加密存储 | 明文存文件 | 存数据库,access_token、refresh_token 做加密 |
| ② | Refresh Token 自动续期 | 快过期时提示重新授权 | 过期前自动用 refresh_token 换新 token |
| ③ | 大文件分片和断点续传 | 合并到内存,限制 100MB | 流式处理、断点续传、失败重试、上传任务恢复 |
| ④ | 客户目录隔离 | 百度应用目录天然隔离 | 业务内部也要严格控制:A 客户不能看到 B 客户目录 |
| ⑤ | 完整上传任务记录 | 无 | 增加任务表,记录客户ID、文件名、状态、失败原因、fs_id 等 |
| ⑥ | 合规和客户告知 | 无 | 授权页面/协议说清:上传到应用目录、可取消授权、不访问私人文件 |
总结
小明这个方案,本质上是用 OAuth 把"客户自己的存储空间"接入公司业务系统。它解决的不是单纯的技术上传问题,而是摄影行业里很实际的交付和成本问题:
- 客户要长期保存照片,公司不想无限扩容
- 客户有自己的网盘,公司有自己的业务系统
- 通过百度网盘开放平台,双方刚好可以连接起来
Demo 已经跑通了从创建客户、扫码授权、保存 token、创建目录、查询容量、上传文件到预览文件的完整流程。后续只要把 token 安全、自动续期、大文件上传、权限隔离和任务追踪补齐,就可以从试水 demo 逐步演进成一个真正可用的客户资料交付系统。
参考链接:
- 百度网盘开放平台
- 百度 OAuth 2.0 文档
- 百度网盘开放接口文档
降本不降质,让存储回归所有者。小明已经在规划下一个客户的接入了。