/
cache.go
115 lines (91 loc) · 2.39 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package middleware
import (
"net/http"
"sort"
"time"
"github.com/labstack/echo"
"github.com/polaris1119/goutils"
"github.com/polaris1119/logger"
"github.com/polaris1119/nosql"
)
type CacheKeyAlgorithm interface {
GenCacheKey(echo.Context) string
}
type CacheKeyFunc func(echo.Context) string
func (self CacheKeyFunc) GenCacheKey(ctx echo.Context) string {
return self(ctx)
}
var CacheKeyAlgorithmMap = make(map[string]CacheKeyAlgorithm)
var LruCache = nosql.DefaultLRUCache
// EchoCache 用于 echo 框架的缓存中间件。支持自定义 cache 数量
func EchoCache(cacheMaxEntryNum ...int) echo.MiddlewareFunc {
if len(cacheMaxEntryNum) > 0 {
LruCache = nosql.NewLRUCache(cacheMaxEntryNum[0])
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
req := ctx.Request()
if req.Method == "GET" {
cacheKey := getCacheKey(ctx)
if cacheKey != "" {
ctx.Set(nosql.CacheKey, cacheKey)
value, compressor, ok := LruCache.GetAndUnCompress(cacheKey)
if ok {
cacheData, ok := compressor.(*nosql.CacheData)
if ok {
// 1分钟更新一次
if time.Now().Sub(cacheData.StoreTime) >= time.Minute {
// TODO:雪崩问题处理
goto NEXT
}
logger.Debugln("cache hit:", cacheData.StoreTime, "now:", time.Now())
return ctx.JSONBlob(http.StatusOK, value)
}
}
}
}
NEXT:
if err := next(ctx); err != nil {
return err
}
return nil
}
}
}
func getCacheKey(ctx echo.Context) string {
cacheKey := ""
if cacheKeyAlgorithm, ok := CacheKeyAlgorithmMap[ctx.Path()]; ok {
// nil 表示不缓存
if cacheKeyAlgorithm != nil {
cacheKey = cacheKeyAlgorithm.GenCacheKey(ctx)
}
} else {
cacheKey = defaultCacheKeyAlgorithm(ctx)
}
return cacheKey
}
func defaultCacheKeyAlgorithm(ctx echo.Context) string {
filter := map[string]bool{
"from": true,
"sign": true,
"nonce": true,
"timestamp": true,
}
form, err := ctx.FormParams()
if err != nil {
return ""
}
var keys = make([]string, 0, len(form))
for key := range form {
if _, ok := filter[key]; !ok {
keys = append(keys, key)
}
}
sort.Sort(sort.StringSlice(keys))
buffer := goutils.NewBuffer()
for _, k := range keys {
buffer.Append(k).Append("=").Append(ctx.FormValue(k))
}
req := ctx.Request()
return goutils.Md5(req.Method + req.URL.Path + buffer.String())
}