资讯动态

restic REST Backend 协议详解:HTTP 仓库的 API 版本协商与全部端点规范

发布时间:2026/9/10 9:40:18 来源:尧图企业网站定制
restic REST Backend 协议详解HTTP 仓库的 API 版本协商与全部端点规范【免费下载链接】resticFast, secure, efficient backup program项目地址: https://gitcode.com/GitHub_Trending/re/restic导读restic 除了支持本地磁盘、SFTP、S3 等仓库还允许连接任何遵循固定 REST API的 HTTP 服务器将其作为备份仓库后端。本文以 doc/REST_backend.rst 为骨架完整讲解该协议中{type}文件类型、v1/v2 两代 API 的版本协商机制、从仓库初始化到 blob 读写的全部 HTTP 端点并结合 internal/backend/rest/rest.go 等客户端源码说明 restic 端如何发起这些请求、如何解析响应。读完本文你可以据此实现一个自定义 REST 仓库服务或深刻理解 restic 访问 HTTP 仓库时的完整网络行为。REST Backend 是什么restic 可以通过 HTTP/HTTPS 与一个实现了下述 REST API 的服务器交互这类服务器作为 restic 的远程仓库。相比 S3、Swift 等公有云对象存储协议REST 协议是完全自定义的因此需要先部署一个专门的 REST 服务器进程例如 restic 官方配套的rest-server再通过修改 URL scheme 让 restic 连上去例如 doc/030_preparing_a_new_repo.rst 中给出的初始化命令$ restic -r rest:http://host:8000/ initrest:前缀后的地址决定协议与访问方式。该文档还给出了 HTTPS、密码保护、多仓库以及 Unix socket 等多种组合$ restic -r rest:https://host:8000/ init $ restic -r rest:https://user:passhost:8000/ init $ restic -r rest:https://user:passhost:8000/my_backup_repo/ init $ restic -r rest:httpunix:///tmp/rest.socket:/my_backup_repo/ init用户名与密码也可以放到环境变量里避免出现在命令行中$ export RESTIC_REST_USERNAMEMY_REST_SERVER_USERNAME $ export RESTIC_REST_PASSWORDMY_REST_SERVER_PASSWORD在客户端解析层internal/backend/rest/config.go 的ParseConfig要求字符串必须以rest:开头prepareURL会保证以/结尾ApplyEnvironment则在 URL 中既未携带用户名也未携带密码时才读取前缀加RESTIC_REST_USERNAME/RESTIC_REST_PASSWORD的环境变量填充认证信息config.go。使用 TLS 时restic 默认用系统 CA 证书校验证书若服务端使用自签证书或自定义 CA可通过--cacert指定证书文件此后系统 CA 将不再参与校验。一个值得注意的事实是REST 服务器在磁盘上使用的目录结构与本地local后端完全一致doc/030_preparing_a_new_repo.rst因此同一份仓库既可以本地直接访问也可以同时通过 HTTP 访问。协议的核心要素{type}、{path} 与目录布局协议文档定义了两个占位符{type}表示文件/blob 的类型合法取值包括{type} 值含义data数据块pack 文件keys密钥文件locks锁文件snapshots快照文件index索引文件config仓库配置文件比较特殊见下{path}是仓库在服务器上的路径目的是让一个服务器同时托管多个相互独立的 restic 仓库。默认路径为/且路径必须以/结尾。客户端对类型与路径的拼接逻辑位于 internal/backend/layout/layout_rest.go。RESTLayout复用了与本地/SFTP 后端一致的defaultLayoutPaths映射见 layout_default.godata、snapshots、index、locks、keys各对应一个同名目录只有config特例其Filename固定为仓库根目录下的configlayout_rest.go。也就是说一个仓库形如{path}/data/… {path}/keys/… {path}/locks/… {path}/snapshots/… {path}/index/… {path}/config注意与本地后端的不同本地后端DefaultLayout为data目录再按文件名前两个字符拆出两层子目录layout_default.go而 REST 布局下data目录是扁平存放的不做两字符子目录拆分。API 版本协商机制Accept 头与 Content-Type 头REST 协议经历过一次演进v1 → v2关键差异在列出 blob端点的返回内容见下文而版本的选择完全依赖 HTTP 头完成服务端无需通过不同 URL 区分版本请求头Accept决定客户端想要的 API 版本application/vnd.x.restic.rest.v1或留空API 版本 1application/vnd.x.restic.rest.v2API 版本 2。对应当返回 JSON 的请求服务器在响应头Content-Type中返回它支持的最高版本值如果Content-Type是其他任何值则视为 API 版本 1。在客户端源码中这两个媒体类型是常量rest.goconst ( ContentTypeV1 application/vnd.x.restic.rest.v1 ContentTypeV2 application/vnd.x.restic.rest.v2 )restic 客户端在发出保存、读取、HEAD、删除、列举等绝大多数请求时都会设置Accept: application/vnd.x.restic.rest.v2例如 rest.go、rest.go、rest.go。而在List处理响应时客户端会检查响应头Content-Type是否为 v2据此决定走listv2还是listv1rest.go——这正是Content-Type 响应头决定协议版本的实现位置。仓库级操作初始化、删除与 config 文件以下端点针对整个仓库{path}层面操作。POST {path}?createtrue —— 创建仓库用于在服务器上新建仓库。客户端以binary/octet-stream类型、空请求体发起 POST并在 URL 查询参数中携带createtrue服务器成功创建结构或仓库已存在时返回200 OK否则返回错误。restic 在restic init时通过客户端Create完成这一调用rest.go它先以Stat检查 config 文件是否已存在若已存在则直接报错 config file already exists防止误初始化覆盖已有仓库随后构造带?createtrue的 POST 请求仅当响应状态为200 OK才视为成功。DELETE {path} —— 删除仓库在服务器端删除整个仓库。成功返回200 OK若服务器未实现该功能返回501 Not Implemented若服务器策略上拒绝删除则返回403 Forbidden。客户端将这类非 200 响应封装为restErrorrest.go。config 文件相关端点HEAD {path}/config仓库存在配置文件时返回200 OK否则返回 HTTP 错误。GET {path}/config返回配置文件内容若存在否则返回 HTTP 错误。响应格式为binary/octet-stream。POST {path}/config将请求体作为配置内容保存成功返回200 OK否则返回 HTTP 错误。客户端Stat就是通过HEAD请求拿Content-Length头作为文件大小来实现的rest.go仓库锁lock流程中判断仓库是否已初始化也正是靠对 config 文件的探测。blob数据文件级操作除了 config 位于仓库根外其余类型都存放在对应子目录中。下文统一写作{path}/{type}/{name}其中{name}是 blob 的文件名restic 中通常是内容的 SHA-256 十六进制哈希。GET {path}/{type}/ —— 列出某类型全部文件API v1返回纯 JSON 字符串数组元素为文件名例如[ 245bc4c430d393f74fbe7b13325e30dbde9fb0745e50caad57c446c93d20096b, 85b420239efa1132c41cea0065452a40ebc20c6f8e0b132a5b2f5848360973ec, 8e2006bb5931a520f3c7009fe278d1ebb87eb72c3ff92a50c30e90f1b8cf3e60, e75c8c407ea31ba399ab4109f28dd18c4c68303d8d86cc275432820c42ce3649 ]API v2返回 JSON 对象数组每个对象含name文件名与size字节大小两个键例如[ { name: 245bc4c430d393f74fbe7b13325e30dbde9fb0745e50caad57c446c93d20096b, size: 2341058 }, { name: 85b420239efa1132c41cea0065452a40ebc20c6f8e0b132a5b2f5848360973ec, size: 2908900 }, { name: 8e2006bb5931a520f3c7009fe278d1ebb87eb72c3ff92a50c30e90f1b8cf3e60, size: 3030712 }, { name: e75c8c407ea31ba399ab4109f28dd18c4c68303d8d86cc275432820c42ce3649, size: 2804 } ]v2 引入的意义在客户端源码里非常清晰listv1在拿到文件名字符串数组后还必须对每一个文件额外发一次HEAD请求来获取大小rest.go而listv2在一次请求的响应中就直接拿到name与sizerest.go大大减少了对小文件仓库做全量列举如restic check、prune遍历索引时的往返次数。List对目录不存在的处理也有细节除rclone/服务器外404被视为目录缺失直接忽略返回rest.go。HEAD {path}/{type}/{name} —— 判断 blob 是否存在若指定类型与名称的 blob 已存储返回200 OK否则返回404 Not Found。若 blob 存在响应头Content-Length会被设置为文件大小。客户端Stat正是依赖此语义获取文件信息。GET {path}/{type}/{name} —— 读取 blob 内容若 blob 存在则返回其内容响应格式binary/octet-stream否则返回404。支持 Range 部分读取如果请求带Range头字段则响应状态码为206而非200响应体只包含请求的范围。这是 restic 恢复与校验大量数据的基础能力。客户端Load/openReader中会把偏移量 长度构造成标准的 HTTP Range 头不带 length 时为bytes{offset}-带 length 时为bytes{offset}-{offsetlength-1}rest.go。响应只接受200 OK或206 Partial Content两种状态码并支持在开启BackendErrorRedesign特性时用416RequestedRangeNotSatisfiable标记越界读取。此外Load在读完数据后会等待一个EOF再关闭响应体以避免 HTTP/2 流被过早关闭导致服务器端出现stream closed错误rest.go。POST {path}/{type}/{name} —— 保存 blob将请求体内容保存为指定类型与名称的 blob成功返回200 OK否则返回 HTTP 错误。请求格式为binary/octet-stream。客户端Save使用application/octet-stream内容类型并显式设置Content-Lengthreq.ContentLength rd.Length()以避免使用 chunked 编码、让服务器提前知道数据规模rest.go。它还用RewindReader支持重试时的请求体重放。注意 REST 后端与对象存储不同其Properties()中HasAtomicReplace为false因为rest-server会阻止覆盖写rest.go。DELETE {path}/{type}/{name} —— 删除 blob从仓库中删除指定 blob成功返回200 OK否则返回 HTTP 错误。客户端Remove直接发送 HTTPDELETE仅接受200 OK作为成功rest.gorestic forget --prune等清理流程最终就依赖该端点回收空间。完整的客户端方法映射把上述端点与 rest.go 中的backend.Backend接口实现一一对应可以快速建立协议 ↔ 代码的映射关系REST 端点客户端方法源码位置POST {path}?createtrueCreaterest.goHEAD {path}/{type}/{name}Statrest.goGET {path}/{type}/{name}含 RangeLoad/openReaderrest.goPOST {path}/{type}/{name}Saverest.goDELETE {path}/{type}/{name}Removerest.goGET {path}/{type}/Listv1/v2 自动探测rest.go仓库整体删除Deleteutil.DefaultDeleterest.go错误语义上也做了归纳restError在404时会被判为文件不存在IsNotExist配合errors.As401、403、416、507InsufficientStorage等被视为永久错误rest.go从而驱动上层重试策略做出正确决策。连接配置与并发控制REST 后端支持通过 restic 的选项机制配置参数。在 config.go 中type Config struct { URL *url.URL Connections uint option:connections help:set a limit for the number of concurrent connections (default: 5) }Connections注册在rest前缀下默认值为 5NewConfig中填充它控制 restic 与 REST 服务器之间允许的最大并发 HTTP 连接数实际通过Backend.Properties().Connections暴露给调度层rest.go。当你的备份并发度高或服务器连接数受限时可在命令行用类似-o rest.connections10的方式调整。测试如何验证这套协议仓库内置了两层测试可作为协议实现者的参考实现internal/backend/rest/rest_int_test.go 用httptest起本地 HTTP 服务直接验证List在不同响应Content-Typev1/v2/未知下的解析分支——例如 v1 响应数组需要额外发出 N 次 HEAD 请求、v2 一次到位internal/backend/rest/rest_test.go 会探测系统是否安装了rest-server可执行文件若存在则以--no-auth --path dir --listen addr启动真实服务进程对完整 REST 后端做与本地后端同等的后端一致性测试Save/Load/Stat/Remove/List 全套并通过backend/test套件校验实现符合backend.Backend契约。如果你的目标是编写一个全新的 REST 仓库服务器最稳妥的路径就是让上述两类测试全部通过。小结REST Backend 是 restic 面向可自托管的任意 HTTP 服务设计的精简协议以Accept/Content-Type头完成 v1/v2 版本协商用 6 种文件类型子目录组织仓库通过 POST/GET/HEAD/DELETE 一组有限动词覆盖创建、读取、写入、删除与列举全部仓库数据并借助 Range 头支持大文件的按需部分读取。本文给出的端点语义可直接作为服务端实现依据而 internal/backend/rest 目录下的客户端代码与测试则是协议行为的权威参考日常使用时可参考 doc/030_preparing_a_new_repo.rst 的 REST Server 小节完成rest:URL 的初始化与访问配置。【免费下载链接】resticFast, secure, efficient backup program项目地址: https://gitcode.com/GitHub_Trending/re/restic创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价