EN
Shopify 知识库 · 排错

Shopify 文件同步后仍显示不同:不要把文件大小当内容身份

以跨店图片同步后的误报为例,说明为什么源店与目标店的文件大小不能直接代表内容是否一致,以及如何用同步映射、源指纹和目标存在性建立可解释的差异状态。

一个文件从源店同步到目标店后,界面仍显示 Content differs,不一定意味着同步失败。常见误区是直接比较源、目标两个 Shopify 文件对象的 fileSize,并把不相等解释成“内容不同”。

Shopify 的 MediaImage 同时涉及原始来源与经过处理、通过 CDN 交付的图片。图片处理是异步的,文件状态会经历处理过程。MediaImage 与 FileStatus 的职责也说明,Shopify 文件不是一个只由上传字节数描述的静态对象。

当目标店根据源店 URL 创建自己的文件资源时,两个店铺分别拥有文件对象与处理生命周期。因而,跨店文件大小不同只能证明返回的大小字段不同,不能单独证明业务内容发生了变化。

先定义“相同”指什么

同步产品至少可能需要回答三种不同问题:

  1. 源文件自上次同步后是否改变。
  2. 上次同步创建的目标文件是否仍然存在。
  3. 目标文件是否被人在目标店单独修改。

这三种问题需要不同证据。把它们压成一次源、目标大小比较,会同时产生误报和漏报。

使用 Mapping 记录同步关系

同步完成后保存一条映射,而不是在下一次预览时重新猜测同名文件之间的关系:

FileMapping
- sourceShop
- sourceFileId
- targetShop
- targetFileId
- sourceFingerprintAtSync
- syncedAt

sourceFingerprintAtSync 表示执行同步时观察到的源指纹。它可以是平台提供的稳定校验值,也可以是应用根据可靠输入计算的摘要;重点是它描述“当时同步的源版本”,而不是拿两个店铺当前的派生字段做等价判断。

一套可解释的状态顺序

没有 mapping
  ├─ 目标没有同名文件 → New
  └─ 目标已有同名文件 → Existing / 待认领

存在 mapping
  ├─ 目标 ID 已不存在 → Missing target / 需要重建
  ├─ 当前源指纹 ≠ 上次源指纹 → Content differs
  ├─ alt 等可独立同步字段不同 → Metadata differs
  └─ 其他情况 → Synced

对应的伪代码:

if (!mapping) {
  return sameNameTarget ? 'existing-unclaimed' : 'new'
}

const target = targetById.get(mapping.targetFileId)
if (!target) return 'missing-target'

if (source.fingerprint !== mapping.sourceFingerprintAtSync) {
  return 'content-differs'
}

if (normalize(source.alt) !== normalize(target.alt)) {
  return 'metadata-differs'
}

return 'synced'

顺序很重要。没有 mapping 的同名文件不能自动视为已经同步,否则应用可能错误认领商家原有资源。目标文件已被删除时,也不应继续显示 Synced。

预览和执行必须共用判断

如果页面自己比较 fileSize,后台任务却根据 mapping 判断源是否变化,用户会看到一种状态,执行时得到另一种结果。正确做法是让服务端产生权威 diff,页面只展示枚举状态和解释。

同步完成后重新读取 diff,并继续使用相同函数判断。这样既能消除“执行成功后仍显示不同”的错觉,也能确保费用预估、可执行项和真实写入使用同一集合。

这套模型仍不能检测目标侧漂移

只保存源指纹,可以回答“源文件自上次同步后是否变化”,但不能证明目标内容未被替换。

如果产品需要检测目标侧漂移,还要在同步完成后记录目标指纹,并在后续读取时取得可比较的目标证据:

sourceFingerprintAtSync
targetFingerprintAtSync
currentSourceFingerprint
currentTargetFingerprint

但目标指纹必须建立在平台能够稳定提供的字段上。不能为了实现漂移检测,又退回到不可靠的文件大小比较。无法获得稳定目标指纹时,应诚实地把状态命名为“源未变化且目标仍存在”,而不是宣称内容完全一致。

同步系统的验收问题

  • 同步后的图片即使大小变化,是否仍能根据源版本显示 Synced?
  • 源文件更新后,是否只标记对应 mapping 为 Content differs?
  • 目标文件被删除后,是否提示重建而不是继续显示 Synced?
  • 无 mapping 的同名文件是否要求明确认领或覆盖?
  • 页面预览、费用预估和执行任务是否使用同一 diff 集合?
  • 应用是否明确说明目前能否检测目标侧人工修改?

差异判断不是 UI 文案问题,而是同步系统对“事实来源”的定义。先确定想证明哪一种一致,再选择对应证据。