fix: 修复签名不匹配的根本原因,改用手动拼接 URL 替代 URLComponents,增加加载重试机制
CI / lint-and-build (push) Has been cancelled

This commit is contained in:
2026-06-30 12:12:06 +06:00
parent 2a53f6a862
commit 5a13a8e6a6
3 changed files with 54 additions and 34 deletions
@@ -66,15 +66,12 @@ actor VODClient {
params["Signature"] = signature params["Signature"] = signature
let host = endpoint() let host = endpoint()
var components = URLComponents() let query = params.sorted(by: { $0.key < $1.key })
components.scheme = "https" .map { "\(VODSignature.percentEncodePublic($0.key))=\(VODSignature.percentEncodePublic($0.value))" }
components.host = host .joined(separator: "&")
components.path = "/" let urlString = "https://\(host)/?\(query)"
components.queryItems = params.sorted(by: { $0.key < $1.key }).map {
URLQueryItem(name: $0.key, value: $0.value)
}
guard let url = components.url else { guard let url = URL(string: urlString) else {
throw VODClientError.invalidResponse throw VODClientError.invalidResponse
} }
return url return url
@@ -93,7 +90,17 @@ actor VODClient {
} }
let decoder = JSONDecoder() let decoder = JSONDecoder()
do {
return try decoder.decode(T.self, from: data) return try decoder.decode(T.self, from: data)
} catch {
if action == "GetPlayInfo" {
print("[VODClient] GetPlayInfo 解码失败: \(error)")
if let raw = String(data: data, encoding: .utf8) {
print("[VODClient] GetPlayInfo 原始响应: \(raw)")
}
}
throw error
}
} }
func searchMedia( func searchMedia(
@@ -26,8 +26,6 @@ struct VODSignature {
let stringToSign = "\(method)&%2F&\(percentEncode(canonicalQuery))" let stringToSign = "\(method)&%2F&\(percentEncode(canonicalQuery))"
print("[VODSignature] stringToSign: \(stringToSign)")
guard let keyData = "\(accessKeySecret)&".data(using: .utf8) else { guard let keyData = "\(accessKeySecret)&".data(using: .utf8) else {
throw VODSignatureError.invalidKey throw VODSignatureError.invalidKey
} }
@@ -41,6 +39,10 @@ struct VODSignature {
return signatureData.base64EncodedString() return signatureData.base64EncodedString()
} }
static func percentEncodePublic(_ value: String) -> String {
percentEncode(value)
}
private static func percentEncode(_ value: String) -> String { private static func percentEncode(_ value: String) -> String {
let allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~" let allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~"
var result = "" var result = ""
@@ -243,7 +243,9 @@ struct VideoListView: View {
private func refreshFromAPI() async { private func refreshFromAPI() async {
isLoading = true isLoading = true
errorMessage = nil errorMessage = nil
loadingStatus = "正在加载视频列表..." let maxRetries = 3
for attempt in 1...maxRetries {
loadingStatus = attempt == 1 ? "正在加载视频列表..." : "重试中... (第 \(attempt)/\(maxRetries) 次)"
var collected: [VideoItem] = [] var collected: [VideoItem] = []
var page = 1 var page = 1
let size = 100 let size = 100
@@ -262,12 +264,21 @@ struct VideoListView: View {
break break
} }
page += 1 page += 1
try? await Task.sleep(for: .milliseconds(200))
} }
allVideos = collected allVideos = collected
applyFilter() applyFilter()
loadingStatus = "" loadingStatus = ""
isLoading = false
return
} catch { } catch {
errorMessage = "加载失败:\(error.localizedDescription)" if attempt < maxRetries {
let delay = UInt64(attempt) * 1_000_000_000
try? await Task.sleep(nanoseconds: delay)
} else {
errorMessage = "加载失败(已重试 \(maxRetries) 次):\(error.localizedDescription)"
}
}
} }
isLoading = false isLoading = false
} }