https://github.com/gin-contrib/cache 缓存
这个项目是Gin的一个Middleware,用于缓存请求结果,目前支持 go-cache 内存缓存(ps:这个库最新的应该是这个地址:patrickmn/go-cache)、memcached 缓存、redis 缓存三种类型。这三个库以后再阅读学习,今天先完成这个项目的学习。缓存用的key采用urlEscape
函数生成,规则为:前缀+冒号+URL(或其MD5)。
示例中仅仅给了一个CachePage
的用法:
r.GET("/cache_ping", cache.CachePage(store, time.Minute, func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
}))
但是cache.go
中还有两个没想明白的函数,不知道该怎么用:
func Cache(store *persistence.CacheStore) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set(CACHE_MIDDLEWARE_KEY, store)
c.Next()
}
}
func SiteCache(store persistence.CacheStore, expire time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
var cache responseCache
url := c.Request.URL
key := urlEscape(PageCachePrefix, url.RequestURI())
if err := store.Get(key, &cache); err != nil {
c.Next()
} else {
c.Writer.WriteHeader(cache.Status)
for k, vals := range cache.Header {
for _, v := range vals {
c.Writer.Header().Add(k, v)
}
}
c.Writer.Write(cache.Data)
}
}
}
Cache
函数使用了一个接口指针作为参数,不知道该怎么传入参数,所以我提了一个issue希望能够得到作者的解答,我觉得也许不需要指针也是可以的。代码只有一行,使用c.Set
将缓存store
的实例保存,应该是为了后续处理使用Set或Get等方法存取自己的缓存数据。
SiteCache
函数定义了一个expire
参数,但实际并没有用到,看代码的意思是每个请求先取缓存,取到就返回缓存,没取到就继续下一步处理。
还有一个CachePageAtomic
函数,与CachePage
函数类似,因为CachePage
函数中在缓存不存在时可能会有替换Writer的情况,使用了sync.Mutex进行加互斥锁保证操作的原子性。
在cache_test.go
中,有一些有用的地方,可以学习,例如测试缓存HTML模板文件:
func TestCacheHtmlFile(t *testing.T) {
store := persistence.NewInMemoryStore(60 * time.Second)
router := gin.New()
router.LoadHTMLFiles("example/template.html")
router.GET("/cache_html", CachePage(store, time.Second*3, func(c *gin.Context) {
c.HTML(http.StatusOK, "template.html", gin.H{"values": fmt.Sprint(time.Now().UnixNano())})
}))
w1 := performRequest("GET", "/cache_html", router)
w2 := performRequest("GET", "/cache_html", router)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, 200, w2.Code)
assert.Equal(t, w1.Body.String(), w2.Body.String())
}
其中performRequest
函数使用httptest包发测试请求、截获响应报文:
func performRequest(method, target string, router *gin.Engine) *httptest.ResponseRecorder {
r := httptest.NewRequest(method, target, nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, r)
return w
}
总而言之,通过这个库,可以了解到如何缓存WEB请求,以后可以在项目中用到部分功能和思想,例如缓存静态页面、数据较为固定的展示页面等等。