mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-04 20:46:37 +08:00
优化
优化
This commit is contained in:
@@ -124,8 +124,12 @@ type downloadURLData struct {
|
||||
} `json:"url"`
|
||||
}
|
||||
|
||||
// GetDownloadURL 获取下载直链(pickcode)。
|
||||
// GetDownloadURL 获取下载直链(pickcode)。命中缓存直接返回,
|
||||
// 避免对同一文件反复换取直链触发 115 风控。
|
||||
func (c *OpenClient) GetDownloadURL(ctx context.Context, pickCode string) (string, error) {
|
||||
if cached := GetDownloadURLCache(pickCode); cached != "" {
|
||||
return cached, nil
|
||||
}
|
||||
params := map[string]string{"pick_code": pickCode}
|
||||
resp, err := c.doAuthJSON(ctx, "POST", ProAPIBase+"/open/ufile/downurl", params, 1)
|
||||
if err != nil {
|
||||
@@ -139,6 +143,7 @@ func (c *OpenClient) GetDownloadURL(ctx context.Context, pickCode string) (strin
|
||||
if first.URL.URL == "" {
|
||||
return "", fmt.Errorf("115: 下载地址为空(文件可能未上传完成或已被删除)")
|
||||
}
|
||||
SetDownloadURLCache(pickCode, first.URL.URL)
|
||||
return first.URL.URL, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// 下载直链进程级缓存。
|
||||
//
|
||||
// 115 的 /open/ufile/downurl 换取结果在一段时间内有效,且换取请求是
|
||||
// WAF 风控重点关注的密集接口。缓存按 pickcode 存直链、避免对同一文件
|
||||
// 反复换取;下载失败(http 403/404 等)时由调用方主动清除对应条目,
|
||||
// 下一轮重试会重新换取链接。
|
||||
package cloud115
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// downloadURLCacheTTL 直链缓存时长。115 直链一般有效 1 小时左右,
|
||||
// 取 45 分钟留出余量。QMediaSync 同类缓存使用 50 分钟。
|
||||
const downloadURLCacheTTL = 45 * time.Minute
|
||||
|
||||
// maxCachedURLs 超过该数量时顺带清理过期条目,防止 map 无限膨胀。
|
||||
const maxCachedURLs = 10000
|
||||
|
||||
type urlCacheEntry struct {
|
||||
url string
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
urlCacheMu sync.Mutex
|
||||
urlCache = map[string]urlCacheEntry{}
|
||||
)
|
||||
|
||||
// GetDownloadURLCache 返回未过期的缓存直链;不存在或已过期返回空串。
|
||||
func GetDownloadURLCache(pickCode string) string {
|
||||
if pickCode == "" {
|
||||
return ""
|
||||
}
|
||||
urlCacheMu.Lock()
|
||||
defer urlCacheMu.Unlock()
|
||||
entry, ok := urlCache[pickCode]
|
||||
if !ok || time.Now().After(entry.expiresAt) {
|
||||
if ok {
|
||||
delete(urlCache, pickCode)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return entry.url
|
||||
}
|
||||
|
||||
// SetDownloadURLCache 写入直链缓存。
|
||||
func SetDownloadURLCache(pickCode, url string) {
|
||||
if pickCode == "" || url == "" {
|
||||
return
|
||||
}
|
||||
urlCacheMu.Lock()
|
||||
defer urlCacheMu.Unlock()
|
||||
if len(urlCache) >= maxCachedURLs {
|
||||
now := time.Now()
|
||||
for k, e := range urlCache {
|
||||
if now.After(e.expiresAt) {
|
||||
delete(urlCache, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
urlCache[pickCode] = urlCacheEntry{url: url, expiresAt: time.Now().Add(downloadURLCacheTTL)}
|
||||
}
|
||||
|
||||
// ClearDownloadURLCache 删除指定 pickcode 的缓存(下载得到非 2xx 时调用)。
|
||||
func ClearDownloadURLCache(pickCode string) {
|
||||
if pickCode == "" {
|
||||
return
|
||||
}
|
||||
urlCacheMu.Lock()
|
||||
defer urlCacheMu.Unlock()
|
||||
delete(urlCache, pickCode)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cloud115
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDownloadURLCache(t *testing.T) {
|
||||
urlCacheMu.Lock()
|
||||
urlCache = map[string]urlCacheEntry{}
|
||||
urlCacheMu.Unlock()
|
||||
|
||||
if got := GetDownloadURLCache("pick1"); got != "" {
|
||||
t.Fatalf("empty cache should return empty, got %q", got)
|
||||
}
|
||||
SetDownloadURLCache("pick1", "http://cdn/1")
|
||||
if got := GetDownloadURLCache("pick1"); got != "http://cdn/1" {
|
||||
t.Fatalf("cache miss, got %q", got)
|
||||
}
|
||||
// 过期条目按未命中处理
|
||||
urlCacheMu.Lock()
|
||||
urlCache["pick1"] = urlCacheEntry{url: "http://cdn/old", expiresAt: time.Now().Add(-time.Second)}
|
||||
urlCacheMu.Unlock()
|
||||
if got := GetDownloadURLCache("pick1"); got != "" {
|
||||
t.Fatalf("expired entry should be a miss, got %q", got)
|
||||
}
|
||||
ClearDownloadURLCache("pick1")
|
||||
if got := GetDownloadURLCache("pick1"); got != "" {
|
||||
t.Fatalf("cleared entry should be a miss, got %q", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user