update_deployment_guide.md 8.3 KB

📦 客户端强制更新部署指南

🎯 更新机制总览

游铛铛客户端采用 Tauri内置更新器 + 后端API服务 的更新架构,支持:

  1. 自动检测更新 - 客户端启动时自动检查
  2. 强制更新 - 关键更新必须安装才能使用
  3. 手工更新 - 用户可选择是否更新
  4. 增量更新 - 只下载变更部分
  5. 签名验证 - 防止恶意更新包

🏗️ 技术架构

graph TB
    subgraph "客户端 (Tauri + Rust)"
        A[应用启动] --> B[检查更新API]
        B --> C{有更新?}
        C -->|是| D[下载更新包]
        C -->|否| E[正常启动]
        D --> F{强制更新?}
        F -->|是| G[强制安装]
        F -->|否| H[用户选择]
    end

    subgraph "后端服务 (FastAPI)"
        I[更新API] --> J[版本检查]
        J --> K[更新包管理]
        K --> L[强制更新标记]
    end

    subgraph "分发服务"
        M[CDN/OSS] --> N[更新包存储]
        N --> O[数字签名]
    end

    A --> I
    I --> M

📋 部署步骤

1. 配置Tauri更新器

更新 src-tauri/tauri.conf.json

{
  "tauri": {
    "updater": {
      "active": true,
      "endpoints": [
        "https://api.youdangdang.com/updates/{{target}}/{{current_version}}"
      ],
      "dialog": true,
      "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkK"
    }
  }
}

配置说明

  • active: 启用更新功能
  • endpoints: 更新检查API地址
  • dialog: 显示更新对话框
  • pubkey: 更新包验证公钥

2. 后端API部署

主要接口

# 检查更新
GET /updates/{target}/{current_version}

# 下载更新包
GET /updates/download/{target}/{version}/{filename}

# 强制用户更新
POST /updates/force/{user_id}

# 更新统计
GET /admin/updates/stats

响应格式示例

{
  "version": "1.0.1",
  "notes": "修复了重要bug,提升了稳定性",
  "pub_date": "2026-01-01T10:00:00Z",
  "platforms": {
    "windows-x86_64": {
      "signature": "数字签名字符串",
      "url": "https://cdn.youdangdang.com/updates/windows-x86_64/1.0.1/update.exe",
      "size": 52428800
    }
  }
}

3. 客户端代码集成

Rust端实现

#[tauri::command]
pub async fn check_for_updates(app: AppHandle) -> Result<UpdateInfo, String> {
    // 自动检查更新逻辑
    match app.updater().check().await {
        Ok(update) => {
            if update.is_update_available() {
                // 检查是否强制更新
                if should_force_update(&update).await {
                    perform_force_update(&app, &update).await?;
                }
                Ok(update.info().clone())
            } else {
                Err("No updates available".to_string())
            }
        }
        Err(e) => Err(format!("Update check failed: {}", e))
    }
}

async fn perform_force_update(app: &AppHandle, update: &Update) -> Result<(), String> {
    // 显示强制更新对话框
    let confirmed = tauri::api::dialog::blocking::ask(
        app.get_window("main").as_ref(),
        "强制更新",
        "检测到重要更新,必须立即更新才能继续使用",
    );

    if !confirmed {
        app.exit(1); // 强制退出
        return Err("User declined forced update".to_string());
    }

    // 下载并安装更新
    update.download_and_install().await?;
    app.restart();
    Ok(())
}

前端调用

// 自动检查(应用启动时)
async function checkForUpdates() {
  try {
    const updateInfo = await invoke('check_for_updates');
    // 处理更新信息
  } catch (error) {
    console.log('No updates available');
  }
}

// 手工检查
async function manualCheck() {
  try {
    const result = await invoke('manual_update_check');
    // 显示更新信息对话框
  } catch (error) {
    // 处理错误
  }
}

4. 强制更新策略

4.1 基于版本的强制更新

# 后端配置
FORCE_UPDATE_VERSIONS = ["1.0.1", "1.1.0"]  # 必须更新的版本

def should_force_update(current_version: str, target_version: str) -> bool:
    """判断是否需要强制更新"""
    try:
        current = parse_version(current_version)
        target = parse_version(target_version)

        # 主要版本升级强制更新
        if target.major > current.major:
            return True

        # 次要版本有安全修复强制更新
        if target.minor > current.minor and "SECURITY" in release_notes:
            return True

        # 特定版本强制更新
        return target_version in FORCE_UPDATE_VERSIONS

    except:
        return False

4.2 基于用户的强制更新

@router.post("/admin/users/{user_id}/force-update")
async def force_user_update(user_id: int, target_version: str = None):
    """强制指定用户更新"""
    # 在数据库中标记用户需要强制更新
    await db.execute(
        "UPDATE users SET force_update_version = ?, force_update_required = 1 WHERE id = ?",
        target_version, user_id
    )

    # 下次客户端启动时会检测到强制更新标志
    return {"success": True, "message": f"User {user_id} marked for forced update"}

5. 更新包管理

5.1 构建更新包

# 构建应用
npm run tauri:build

# 生成更新包(Tauri会自动生成)
# 输出: src-tauri/target/release/bundle/msi/*.msi
#       src-tauri/target/release/bundle/appimage/*.AppImage
#       src-tauri/target/release/bundle/dmg/*.dmg

5.2 数字签名

# 使用私钥签名更新包
tauri signer sign -k private_key.pem update.exe

# 生成签名文件
tauri signer generate -k private_key.pem

5.3 分发部署

# 上传到CDN/OSS
aws s3 cp update.exe s3://youdangdang-updates/windows-x86_64/1.0.1/

# 更新后端数据库
INSERT INTO update_packages (version, platform, url, signature, size)
VALUES ('1.0.1', 'windows-x86_64', 'https://...', 'signature...', 52428800);

🔒 安全保障

1. 更新包验证

  • 数字签名: 确保更新包未被篡改
  • HTTPS传输: 防止中间人攻击
  • 完整性检查: SHA256哈希验证

2. 回滚机制

  • 版本记录: 保存历史版本信息
  • 自动回滚: 更新失败自动恢复
  • 手动回滚: 管理员可强制回滚

3. 权限控制

  • 管理员控制: 只有管理员能发布更新
  • 用户分组: 支持不同用户组的不同更新策略
  • 灰度发布: 先小范围发布,确认稳定后再全量

📊 监控统计

更新成功率统计

-- 更新统计查询
SELECT
    version,
    platform,
    COUNT(*) as total_users,
    SUM(CASE WHEN update_status = 'success' THEN 1 ELSE 0 END) as success_count,
    SUM(CASE WHEN update_status = 'failed' THEN 1 ELSE 0 END) as failed_count,
    AVG(update_time) as avg_update_time
FROM update_logs
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY version, platform;

实时监控指标

  • 更新请求数: 每分钟检查更新次数
  • 下载成功率: 更新包下载成功比例
  • 安装成功率: 更新安装成功比例
  • 用户覆盖率: 已更新用户占总用户比例

🚀 最佳实践

1. 更新频率控制

  • 大版本: 每月1次,强制更新
  • 小版本: 每周1次,可选更新
  • 补丁版本: 按需发布,可选更新

2. 用户体验优化

  • 进度显示: 显示下载和安装进度
  • 中断恢复: 支持断点续传
  • 低带宽优化: 压缩更新包大小

3. 错误处理

  • 网络异常: 自动重试机制
  • 安装失败: 提供详细错误信息和解决建议
  • 版本冲突: 智能检测和处理版本冲突

🛠️ 故障排除

常见问题

1. 更新检查失败

# 检查网络连接
curl https://api.youdangdang.com/updates

# 检查API响应
curl "https://api.youdangdang.com/updates/windows-x86_64/1.0.0"

2. 下载失败

# 检查CDN访问
curl -I https://cdn.youdangdang.com/updates/windows-x86_64/1.0.1/update.exe

# 检查签名验证
tauri signer verify -k public_key.pem update.exe

3. 安装失败

# 检查文件权限
ls -la update.exe

# 检查磁盘空间
df -h

# 查看安装日志
tail -f /tmp/tauri-updater.log

此指南提供了完整的客户端强制更新部署方案,确保安全、稳定、高效的更新体验。