首页
/ Strapi Remote Destination Provider 详解:通过 WebSocket 将数据推送到远程 Strapi 实例

Strapi Remote Destination Provider 详解:通过 WebSocket 将数据推送到远程 Strapi 实例

2026-09-04 15:12:28作者:温玫谨Lighthearted

Strapi 的数据传输(data-transfer)模块支持在多个 Strapi 实例之间整站迁移内容、媒体与配置。其中 remote destination provider(远程目标提供者)负责把本机数据通过 WebSocket 推送到远端 Strapi,并在传输的各个阶段(assets、entities、links、configuration)之间协调状态流转。本文基于官方文档对该 provider 的选项定义,并结合 remote-destination 源码、dispatcher 工具与 CLI 命令逐层展开:读完后你将掌握该 provider 的全部配置项(restorestrategyurlauthretryMessageOptions)、认证与安全前提、底层推送协议与批处理策略,并知道如何通过 strapi transfer 命令实际操作。

1. Provider 定位:数据传输中的"推"方向

在 data-transfer 模块中,provider 分为 source(数据源)与 destination(数据目标)两类,每类又各有本地(local)与远程(remote)实现。remote destination provider 的角色在文档中描述得很直接:它连接远端 Strapi 的 WebSocket 服务器,发送消息以在传输阶段之间流转并推送数据。

从源码结构看,该 provider 实现于 RemoteStrapiDestinationProvider,其标识为 name = 'destination::remote-strapi'type = 'destination'。它与 remote source provider 构成一对:source 用于 pull(从远端拉数据),destination 用于 push(向远端推数据)。传输路径常量定义在 constants.ts

export const TRANSFER_PATH = '/transfer/runner' as const;
export const TRANSFER_METHODS = ['push', 'pull'] as const;

destination 连接的是远端 admin URL 加 /transfer/runner/push,而 source 连接 /transfer/runner/pull。远端真正落地数据的逻辑由 push handler 负责——从源码结构看,PushHandler 内部复用了 local destination provider(createLocalStrapiDestinationProvider),也就是说"远程目标"在远端最终退化成一个"本地目标"来写库,这是理解整个 push 流程的关键。

2. Provider 选项:IRemoteStrapiDestinationProviderOptions

文档给出的选项接口如下(继承自 local destination provider 的 restorestrategy,另加远程专属项):

interface ITransferTokenAuth {
  type: 'token'; // the name of the auth strategy
  token: string; // the transfer token
}

export interface IRemoteStrapiDestinationProviderOptions
  extends Pick<ILocalStrapiDestinationProviderOptions, 'restore' | 'strategy'> {
  url: URL; // the url of the remote Strapi admin
  auth?: ITransferTokenAuth;
  retryMessageOptions?: {
    retryMessageTimeout: number; // milliseconds to wait for a response from a message
    retryMessageMaxRetries: number; // max number of retries for a message before aborting transfer
  };
}

各选项含义与源码中的补充细节:

选项 类型 说明
strategy 'restore' 冲突处理策略。从 local-destination 源码 可见 VALID_CONFLICT_STRATEGIES = ['restore'],即目前唯一可用的策略是 restore(先清空目标数据再写入)
restore restore.IRestoreOptions 目标端清理选项。使用 restore 策略时为必需项;从源码可见它支持按 entities.include / entities.exclude 筛选内容类型,以及 assets 控制媒体清理范围
url URL 远端 Strapi admin 的地址,必须以 http(s) 协议书写(见下节)
auth ITransferTokenAuth 可选的 token 认证。不传时 provider 会尝试以"公共访问"方式连接
retryMessageOptions 对象 消息级重试配置,控制单条消息超时与最大重试次数(默认值见第 5 节)

需要说明的是,当前仓库源码中的接口比文档多了两项,属于实现演进(该文档标注为 experimental):

  • onTransferPhase:同样从 local provider Pick 过来,用于向 CLI / UI 输出人类可读的传输阶段进度信息,例如 bootstrap 时的 "Remote: waiting for server to clear data and prepare destination…";
  • verifyChecksums?: boolean:是否启用按文件的流式校验和,并要求对端在接收时验证(见第 7 节)。

auth 的类型定义见 protocol/auth.ts,目前唯一支持的认证策略就是 token

3. URL 规则:http(s) 写 URL,ws(s) 建连接

文档特别强调:url 必须包含 httpshttp 协议,provider 会将其转换为 wssws 来建立连接;并且强烈建议使用安全连接,因为 transfer token 拥有极高的访问权限。

bootstrap 方法 中的具体实现印证了这一规则:

const { url, auth } = this.options;
const validProtocols = ['https:', 'http:'];

if (!validProtocols.includes(url.protocol)) {
  throw new ProviderValidationError(`Invalid protocol "${url.protocol}"`, {
    check: 'url',
    details: { protocol: url.protocol, validProtocols },
  });
}
const wsProtocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${wsProtocol}//${url.host}${trimTrailingSlash(url.pathname)}${TRANSFER_PATH}/push`;

要点有三:

  1. 直接传 ws://wss:// 的 URL 会抛出 ProviderValidationErrorcheck: 'url');
  2. url.pathname 末尾的斜杠会被 trimTrailingSlash 去掉,避免拼出双斜杠;
  3. 最终 WebSocket 地址 = 协议转换后的 host + pathname + /transfer/runner/push

这一行为有单测直接锁定:index.test.ts 断言 http://strapi.com/admin 会连接 ws://strapi.com/admin/transfer/runner/pushhttps://... 会连接 wss://...,而 ws:// 输入的 bootstrap 会以 Invalid protocol 报错拒绝。

4. 认证:transfer token 与 Bearer 头

auth 可选但强烈推荐。bootstrap 中对认证的分支处理如下(见 bootstrap 源码):

// No auth defined, trying public access for transfer
if (!auth) {
  ws = await connectToWebsocket(wsUrl, undefined, this.#diagnostics);
}
// Common token auth, this should be the main auth method
else if (auth.type === 'token') {
  const headers = { Authorization: `Bearer ${auth.token}` };
  ws = await connectToWebsocket(wsUrl, { headers }, this.#diagnostics);
}
// Invalid auth method provided
else {
  throw new ProviderValidationError('Auth method not available', { ... });
}
  • 不传 auth:尝试公共访问(适用于远端允许匿名 transfer 的配置);
  • auth.type === 'token':在 WebSocket 升级请求上附加 Authorization: Bearer <token> 头,源码注释明确这是"主要的认证方式";
  • 其他 auth.type:直接抛 ProviderValidationError

这里的 token 即 Strapi 后台生成的 Transfer Token。在管理面板的 Settings 中可创建、查看与设置有效期(见 TransferTokens 管理页面token 服务),远端通过 data-transfer 认证策略 校验该 token。

连接层的错误映射同样值得注意:connectToWebsocket 会把 WebSocket 升级时的 HTTP 状态码翻译成可读的初始化错误——401 为 "Authentication Error"(token 无效)、403 为 "Authorization Error"(token 权限/范围不符)、404 为 "Data transfer is not enabled on the remote host"(远端未开启数据传输功能)。排查连不上远端的问题时,先对号入座这三个状态码。

5. retryMessageOptions 与消息分发器的重试机制

retryMessageOptions 的两个字段语义在文档中已给出,而它们的默认值可以直接从 createDispatcher 的签名看出:

export const createDispatcher = (
  ws: WebSocket,
  retryMessageOptions: RetryMessageOptions = {
    retryMessageMaxRetries: 5,
    retryMessageTimeout: 30000, // 30 秒
  },
  ...
)

即不显式传参时,单条消息 30 秒未收到响应就重发,最多重发 5 次,仍无响应则以 ProviderError('Request timed out') 中止传输。从源码结构看,其机制是:每条消息带随机 uuid 发出后,dispatcher 以 retryMessageTimeout 为周期重发同一份字符串化 payload,直到收到 uuid 匹配的响应(清除定时器)或超过 retryMessageMaxRetries。所有传输消息(transfer action / step)都会自动附带当前 transferIDattachTransfer: true),保证远端把消息挂到正确的传输会话上。

bootstrap 阶段正是用这套 dispatcher 完成四件事(见 bootstrap 尾部):创建 dispatcher → initTransfer() 拿到 transferID → setTransferProperties({ id, kind: 'push' }) → 发送 bootstrap 动作等待远端就绪。

6. init 协商:策略下发与能力探测

initTransfer 通过 command: 'init'strategyrestoretransfer: 'push' 下发给远端,远端据此初始化一次 push 传输并返回 transferID。同一消息里还做两项能力协商:

  • 校验和协商:本地请求 checksums: true 时,只有远端回显 checksums: true 才真正启用;否则记录诊断警告 "[Data transfer][push] Checksums were requested but the remote does not support checksum negotiation",继续无校验和传输。
  • 资产块编码协商:客户端始终声明 assetEncoding: 'base64'。若远端回显 'base64' 则使用紧凑的 base64 分块格式;若不回显(老版本远端会静默丢弃该字段),则回退到 legacy 的 { type: 'Buffer', data: number[] } JSON 形状,并输出警告说明大文件可能在远端 JSON.parse 时 OOM,建议升级远端。这个版本兼容逻辑在源码注释中有明确说明(引用了引入 base64 格式的 PR #23479)。

init 响应中没有 transferID 时,抛出 ProviderTransferError('Init failed, invalid response from the server')

7. 推送流程:阶段、批处理与统计核对

拿到 transferID 后,provider 通过 createEntitiesWriteStream / createLinksWriteStream / createConfigurationWriteStream / createAssetsWriteStream 四个写流接收引擎的数据,每个写流对应一个传输阶段(step),消息按 start → stream → end 三段式发送:

  • #startStepdispatchTransferStep({ action: 'start', step }),失败会把错误(字符串或 Error)包装为 ProviderTransferError 返回;
  • #streamStep:发送 { action: 'stream', step, data },同时累加本地 stats[step].count
  • #endStep:发送 { action: 'end' },远端返回 { ok, stats },其中 stats 为远端的收发计数。

非资产阶段的批处理(entities / links / configuration)由私有方法 #writeStream 实现,源码给出了三个固定的批处理上限常量及其设计动机注释:

const STREAM_STEP_MAX_BATCH_BYTES = 512 * 1024; // 单条消息载荷上限 512KB
const STREAM_STEP_MAX_BATCH_ITEMS = 100;         // 单条消息条目上限
const STREAM_STEP_MAX_BATCH_AGE_MS = 450;        // 批次最老条目等待上限

三者取"先到者"触发 flush:批次 JSON 序列化后字节数 ≥ 512KB、条目数 ≥ 100、或首条数据已滞留 ≥ 450ms(保证 UI 进度与网络进度差距有界)。写入流关闭时,先 flush 剩余批次,再 end,并做一致性核对:若远端返回的 stats.started / stats.finished 与本地发送计数 count 不一致,回调报错 Data missing: sent X entities, received Y and saved Z——即传输结束后会做一次端到端数量校验。

资产阶段单独处理(createAssetsWriteStream):每个 IAsset 先推送 { action: 'start' }(含 filename、filepath、stats、metadata),随后按流分块推送(批次目标 1MB),最后推送 { action: 'end' }。启用 verifyChecksums 时,分块过程中用 createHash('sha256') 增量计算哈希,并在 end 消息中携带 { checksum: { algorithm: 'sha256', value } } 供远端验证;远端在 push handler 中维护 assetChecksums 增量状态与之对应。分块编码函数选择(base64 或 legacy)取决于第 6 节 init 协商的 #assetEncoding 结果。

close() 则负责优雅收尾:发送 close 动作与 command: 'end'(携带 transferID),再等待 WebSocket 关闭(见 close 实现)。此外 provider 还暴露 beforeTransfer()(远端清数据与准备目标,期间通过 onTransferPhase 汇报进度)、rollback()getMetadata()getSchemas(),分别对应 push 端合法动作清单 ['bootstrap', 'close', 'rollback', 'beforeTransfer', 'getMetadata', 'getSchemas'](见 push.ts)。

8. 实战入口:strapi transfer CLI

上述 provider 的常规使用入口是 strapi transfer 命令,命令定义在 transfer/command.ts(实际路径为 packages/core/strapi/src/cli/commands/transfer/command.ts)。与 destination 方向直接相关的选项有:

  • --to <destinationURL>:目标远程 Strapi 的 URL(解析为 URL 对象,即本 provider 的 url 选项);
  • --to-token <token>:目标端的 transfer token(即 auth.token);
  • --no-checksums:禁用端到端资产校验和(对应 verifyChecksums);
  • --verbose--force--only / --exclude--only-content-types / --exclude-content-types--throttle 等通用选项。

命令行为要点(均来自源码 preAction 钩子):

  1. --from--to 只能二选一,否则报错 "Only one remote source (from) or destination (to) option may be provided";
  2. --to 的 URL 会被 assertUrlHasProtocol 校验必须带 http(s) 协议,缺 --to-token 时会以密码输入方式交互式索取;
  3. 确认提示为 "The transfer will delete existing data from the remote Strapi! Are you sure you want to proceed?"——再次提醒 restore 策略对远端数据是破坏性的;
  4. 交互式场景下支持从环境变量 STRAPI_TRANSFER_URLSTRAPI_TRANSFER_TOKEN 读取配置,未提供 URL 时会引导选择 push / pull 方向。

一个典型的推送(destination)调用形态:

strapi transfer \
  --to https://remote-strapi.example.com/admin \
  --to-token <transfer-token>

9. 小结与延伸阅读

remote destination provider 把"远程写库"抽象成一次带认证的 WebSocket 会话:http(s) URL 自动转 ws(s) 并拼接 /transfer/runner/push,token 以 Bearer 头认证,消息经具备默认 5 次 / 30 秒重试策略的 dispatcher 分发,数据按阶段 start/stream/end 三段式推送,并在批次上限(512KB / 100 条 / 450ms)与 1MB 资产批次之间做吞吐与延迟的平衡,最后以远端 stats 做数量核对、可选 SHA-256 校验和兜底。安全上必须使用 https 连接妥善保管 transfer token,因为该 token 足以清空并改写远端数据。

相关文档与源码可继续深入:

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384