268 lines
7.1 KiB
Markdown
268 lines
7.1 KiB
Markdown
# 更新检查 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) |
|
||
|
||
### 响应格式
|
||
|
||
**有更新:**
|
||
```json
|
||
{
|
||
"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哈希值"
|
||
}
|
||
}
|
||
```
|
||
|
||
**无需更新:**
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "ok",
|
||
"data": {
|
||
"update": false
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误响应:**
|
||
```json
|
||
{
|
||
"code": 500,
|
||
"msg": "no asset found for this platform and architecture"
|
||
}
|
||
```
|
||
|
||
## 🧪 测试示例
|
||
|
||
### PowerShell 测试
|
||
|
||
```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 测试
|
||
|
||
```bash
|
||
# 测试更新检查
|
||
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`
|
||
|
||
### 示例
|
||
|
||
```go
|
||
// 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. 准备数据
|
||
|
||
```powershell
|
||
# 创建应用
|
||
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. 客户端检查更新
|
||
|
||
```powershell
|
||
# 用户当前使用 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 为空 | 检查资源数据完整性 |
|
||
|
||
## ✅ 改进总结
|
||
|
||
### 修复前的问题
|
||
|
||
```go
|
||
// ❌ 错误的版本比较
|
||
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 可能为空
|
||
```
|
||
|
||
### 修复后
|
||
|
||
```go
|
||
// ✅ 正确的版本比较
|
||
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
|
||
}
|
||
```
|
||
|
||
现在更新检查功能已经完全可靠!🎉
|