====== 既有文件互传 HTTP 协议参考 ====== 此页供兼容已部署的文件互传功能,区别于新 [[developer/transfers|持久上传门面]]。旧功能是账号范围内的LAN浏览器互传,配对设备不会获得NAS会话,APP不要用peer令牌冒充NAS登录。新客户端优先按capabilities选择统一门面,只有需要兼容旧入口时使用本页。 ===== 两个前缀与配对 ===== NAS会话使用 /api/v1/file-transfer,已批准设备使用 /api/v1/file-transfer/peer。NAS请求携带NAS Bearer;peer可以携带Authorization: Bearer加64hex claimToken,浏览器也可使用HttpOnly、SameSite=Strict的apuos_transfer cookie。Cookie写请求需要真实同源Origin;显式Bearer请求不依赖cookie。令牌不能出现在URL中。 - NAS POST /api/v1/file-transfer/invites,正文空对象,返回16位大写hex code、expires(毫秒)与peerPath:/transfer。邀请有效10分钟,同账号最多8个。 - 客户端生成32字节随机claimToken(64小写hex),POST /api/v1/file-transfer/join,正文为code、name、claimToken。name最多120字节且非空,返回id、verificationCode、state:pending。 - NAS核对设备验证码后POST /api/v1/file-transfer/devices/{id}/decision,正文{accept:true}。同账号pending/approved设备最多32个,批准有效7天。 - 客户端GET /api/v1/file-transfer/join/{id},Bearer为claimToken。返回id、state、name、expires;浏览器获批准后另设置cookie。只有approved才可使用peer数据接口。 NAS DELETE /api/v1/file-transfer/devices/{id}撤销设备。peer POST /peer/logout撤销自身。NAS POST /devices/{id}/reconnect,正文空对象,给仍approved的原设备生成一次性10分钟重连code;客户端用新claimToken走join,保留deviceId并换密钥、延长7天。撤销设备不能藉此复活。 ===== 快照、任务与原字段 ===== GET前缀返回actor、devices、items、chunkSize、maxFileBytes、quotaBytes、downloadResume:http-range、transport:lan-browser、canSend、canSaveToNAS;NAS还可见lanHosts。设备项有id、name、state、expires、lastSeen、online、verificationCode。online是心跳短期判断,不是文件已经传完。POST前缀/heartbeat更新lastSeen并返回time(毫秒)。 POST /transfers Content-Type: application/json {"recipientId":"nas","name":"file.bin","size":123,"fingerprint":"<64hex>","nonce":"<32hex>"} 收件人为nas自动accepted,否则需同owner已批准设备且初始pending。nonce在同owner/sender内实现创建幂等,相同nonce元数据不同返回409。Transfer公开字段为id、sender、senderName、recipient、name、size、received、fingerprint、status、sha256、prefixDigest、createdAt、updatedAt、error、chunkSize;owner和nonce不公开,source只给NAS actor。 旧浏览器fingerprint计算为SHA256(UTF8十进制文件长度 || SHA256前256KiB || SHA256后256KiB),不足256KiB时前后片段可能相同,仍按公式两次拼接。服务端只校验fingerprint格式,最终完整校验仍靠finish;不要把采样fingerprint当作完整文件内容证明。续传还要验证已确认2MiB块的前缀链。 ===== 分块、动作与完成 ===== GET前缀/transfers/{id}查询,PUT前缀/transfers/{id}/chunks/{offset}发送原始2MiB块与X-Chunk-SHA256。顺序、大小、重试和摘要链规则见 [[developer/transfers|统一持久上传]],旧底层允许0字节至64GiB。POST前缀/transfers/{id}/finish提交{sha256:完整64hex},返回202 verifying;轮询到ready才是完整缓存。 POST前缀/transfers/{id}/action提交action:接收方可accept/reject pending任务;发送者可pause accepted/uploading/importing任务、resume paused/verification_failed任务;发送者或NAS可cancel;接收方可把ready标为received;NAS或发送者可delete任务。delete在后台校验活跃时可能返回transfer_busy;cancel/reject删除缓存但保留状态记录。received是接收确认,不证明已保存到NAS目录。 ===== NAS源导出与缓存下载 ===== NAS POST /api/v1/file-transfer/nas-transfers,正文{recipientId,nonce,source:{root,path,share}},只支持文件源,不递归打包文件夹。NAS使用原文件列表与下载代理读取,检查源元数据与Range响应,写入相同传输缓存。任务source包含内部参数和原元数据etag,APP peer不可见。暂停或中断后,NAS POST /transfers/{id}/export重新启动已有源导出,仍需源未改变与相同NAS会话能力。 GET前缀/transfers/{id}/download只读ready/received缓存。支持单Range(起止、开放结尾或后缀),不支持逗号多段。返回Content-Length、Accept-Ranges、Content-Disposition、强ETag(完整SHA256)和X-File-SHA256;206另含Content-Range。If-Range匹配强ETag才应用范围,不匹配时200全文件;If-None-Match匹配时304。边界错误416,不要继续向旧部分文件追加。每个读取块重新核验授权,可在撤销后中断。 NAS可POST /transfers/{id}/download-ticket(空对象),得到url和expires并设置单文件HttpOnly cookie,供浏览器原生下载。有效期8小时但仍受原NAS会话和实时权限限制;URL不含NAS令牌。原生APP通常直接带Bearer下载,不需要此cookie票据。 ===== 保存到NAS与旧流程限制 ===== NAS先GET/POST /api/v1/file-transfer/receive-directory,保存账号目标{root,path,share}。NAS再POST /transfers/{id}/save,正文{confirm:true},要求收件人为nas且ready/received,并具备files.write与实际目录权限。成功结果为saved:true、实际path、name,以及当前实现返回的校验信息;底层使用POST /files/receive流式校验并禁止覆盖。 peer没有NAS Principal,不能自行调用save或修改目标。旧save依赖可变账号默认目录,且没有新版manifest的持久提交回执;响应丢失后重试可能同名409,不能判成功。新APP需要明确目标、可恢复目录任务和提交幂等时,请使用新版门面,不为peer私自注入主机管理员权限。 ===== 失败处理 ===== 常见码包括transfer_join_required、transfer_device_revoked、transfer_origin_denied、transfer_invite_invalid/expired、transfer_nonce_conflict、transfer_not_uploading、transfer_offset_conflict、transfer_chunk_conflict、transfer_checksum_mismatch、transfer_data_missing、transfer_incomplete、transfer_not_ready、transfer_space_insufficient。保留HTTP状态区分认证、冲突与容量失败;断网后先读服务器状态再重传,不能把所有错误都退化成“重新创建一个任务”。