Files
nebula/docs/UPDATE_CHECK.md
2026-03-10 16:26:48 +08:00

7.1 KiB
Raw Permalink Blame History

更新检查 API 文档

🔧 修复内容

已修复的 Bug

  1. 版本比较逻辑错误

    • 之前:使用字符串比较("1.10.0" < "1.9.0" 错误)
    • 现在实现语义化版本号比较semver
  2. Asset 查询错误处理缺失

    • 之前:查询失败时返回空 URL
    • 现在:正确处理错误并返回明确的错误信息
  3. 参数验证缺失

    • 现在验证所有必需参数app, version, platform, arch
  4. 排序逻辑优化

    • 之前:按 version 字符串排序
    • 现在:按 pub_date 排序,更准确
  5. 响应格式统一

    • 现在使用统一的响应格式,并添加 checksum 字段

📝 API 使用

端点

GET /api/check-update

请求参数

参数 类型 必需 说明
app string 应用 ID
version string 当前版本号
platform string 平台windows/darwin/linux
arch string 架构amd64/arm64/386

响应格式

有更新:

{
  "code": 0,
  "msg": "ok",
  "data": {
    "update": true,
    "version": "1.2.0",
    "notes": "更新说明\n- 新功能\n- Bug修复",
    "url": "http://localhost:9050/files/releases/2/windows-amd64/app.exe",
    "checksum": "sha256哈希值"
  }
}

无需更新:

{
  "code": 0,
  "msg": "ok",
  "data": {
    "update": false
  }
}

错误响应:

{
  "code": 500,
  "msg": "no asset found for this platform and architecture"
}

🧪 测试示例

PowerShell 测试

# 测试更新检查(需要更新)
$params = @{
    app = "test-app"
    version = "1.0.0"
    platform = "windows"
    arch = "amd64"
}
$query = ($params.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" }) -join "&"
Invoke-RestMethod -Uri "http://localhost:9050/api/check-update?$query"

# 测试更新检查(已是最新)
$params = @{
    app = "test-app"
    version = "2.0.0"
    platform = "windows"
    arch = "amd64"
}
$query = ($params.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" }) -join "&"
Invoke-RestMethod -Uri "http://localhost:9050/api/check-update?$query"

# 测试不存在的平台
$params = @{
    app = "test-app"
    version = "1.0.0"
    platform = "windows"
    arch = "arm"  # 假设没有这个架构的版本
}
$query = ($params.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" }) -join "&"
Invoke-RestMethod -Uri "http://localhost:9050/api/check-update?$query"

curl 测试

# 测试更新检查
curl "http://localhost:9050/api/check-update?app=test-app&version=1.0.0&platform=windows&arch=amd64"

# 测试参数缺失
curl "http://localhost:9050/api/check-update?app=test-app"

📦 版本号比较规则

实现了完整的语义化版本号semver比较

支持的版本格式

  • 1.0.0 - 标准格式
  • v1.0.0 - 带 v 前缀
  • 1.0.0-beta.1 - 预发布版本
  • 1.0.0+build.123 - 构建元数据

比较规则

  1. 主版本号优先2.0.0 > 1.9.9
  2. 次版本号次之1.10.0 > 1.9.0
  3. 修订号最后1.0.10 > 1.0.9
  4. 预发布版本1.0.0 > 1.0.0-rc.1 > 1.0.0-beta.1 > 1.0.0-alpha.1

示例

// pkg/util/version.go

CompareVersion("1.10.0", "1.9.0")      // 返回 1 (1.10.0 > 1.9.0)
CompareVersion("2.0.0", "1.99.99")     // 返回 1 (2.0.0 > 1.99.99)
CompareVersion("1.0.0", "1.0.0-beta")  // 返回 1 (正式版 > 预发布版)
CompareVersion("v1.0.0", "1.0.0")      // 返回 0 (相等)

IsNewerVersion("1.0.0", "1.1.0")       // 返回 true
IsNewerVersion("1.1.0", "1.0.0")       // 返回 false

🔄 完整更新流程

1. 准备数据

# 创建应用
Invoke-RestMethod -Method POST -Uri "http://localhost:9050/api/apps" `
  -ContentType "application/json" `
  -Body '{"id":"my-app","name":"我的应用","description":"测试"}'

# 创建版本 1.0.0
Invoke-RestMethod -Method POST -Uri "http://localhost:9050/api/releases" `
  -ContentType "application/json" `
  -Body '{"appID":"my-app","version":"1.0.0","notes":"初始版本","channel":"stable","pubDate":"2026-03-10T10:00:00Z"}'

# 上传 1.0.0 的 Windows 版本
$form = @{
    file = Get-Item -Path "D:\app-v1.0.0.exe"
    platform = "windows"
    arch = "amd64"
}
Invoke-RestMethod -Uri "http://localhost:9050/api/releases/1/assets/upload" -Method Post -Form $form

# 创建版本 1.1.0
Invoke-RestMethod -Method POST -Uri "http://localhost:9050/api/releases" `
  -ContentType "application/json" `
  -Body '{"appID":"my-app","version":"1.1.0","notes":"新增功能","channel":"stable","pubDate":"2026-03-11T10:00:00Z"}'

# 上传 1.1.0 的 Windows 版本
$form = @{
    file = Get-Item -Path "D:\app-v1.1.0.exe"
    platform = "windows"
    arch = "amd64"
}
Invoke-RestMethod -Uri "http://localhost:9050/api/releases/2/assets/upload" -Method Post -Form $form

2. 客户端检查更新

# 用户当前使用 1.0.0,检查更新
$response = Invoke-RestMethod -Uri "http://localhost:9050/api/check-update?app=my-app&version=1.0.0&platform=windows&arch=amd64"

if ($response.data.update) {
    Write-Host "发现新版本: $($response.data.version)"
    Write-Host "更新说明: $($response.data.notes)"
    Write-Host "下载地址: $($response.data.url)"
    Write-Host "校验和: $($response.data.checksum)"
    
    # 下载更新
    Invoke-WebRequest -Uri $response.data.url -OutFile "app-update.exe"
    
    # 验证校验和(可选)
    $hash = (Get-FileHash -Path "app-update.exe" -Algorithm SHA256).Hash
    if ($hash.ToLower() -eq $response.data.checksum) {
        Write-Host "✅ 文件校验通过"
    } else {
        Write-Host "❌ 文件校验失败"
    }
} else {
    Write-Host "✅ 当前已是最新版本"
}

🛡️ 错误处理

所有可能的错误情况:

错误信息 原因 解决方法
app is required 缺少 app 参数 提供应用 ID
version is required 缺少 version 参数 提供当前版本号
platform is required 缺少 platform 参数 提供平台信息
arch is required 缺少 arch 参数 提供架构信息
no release found for this app 应用没有发布版本 先创建版本发布
no asset found for this platform and architecture 没有对应平台的安装包 上传对应平台的资源
asset URL is empty 资源记录存在但 URL 为空 检查资源数据完整性

改进总结

修复前的问题

// ❌ 错误的版本比较
if req.Version >= latest.Version {  // "1.10.0" < "1.9.0" 
    return &CheckResponse{Update: false}, nil
}

// ❌ 没有错误处理
db.Where(...).First(&asset)  // 忽略了错误
return &CheckResponse{URL: asset.URL}  // URL 可能为空

修复后

// ✅ 正确的版本比较
if !util.IsNewerVersion(req.Version, latest.Version) {
    return &CheckResponse{Update: false}, nil
}

// ✅ 完整的错误处理
err = db.Where(...).First(&ast).Error
if err != nil {
    if errors.Is(err, gorm.ErrRecordNotFound) {
        return nil, errors.New("no asset found...")
    }
    return nil, err
}

现在更新检查功能已经完全可靠!🎉