Golang静态资源缓存数据不一致,页面渲染异常求助
静态资源缓存数据不一致问题原因分析
核心问题根源
你的代码中缓存的响应数据(Header和Body)直接引用了Fiber框架上下文的内部对象,而Fiber为了性能会复用上下文对象池,导致后续请求的响应数据覆盖了缓存中的引用内容,最终出现缓存数据异常。
具体问题点:
- Header引用共享:
c.GetRespHeaders()返回的是Fiber响应对象内部的Header映射引用,而非独立副本。当后续请求复用该上下文时,新的响应Header会直接修改缓存中的映射内容——比如日志里的Content-Type被篡改成image/jpegn/javascript,就是两个不同请求的Header值被混写了。 - Body引用共享:
c.Response().Body()返回的是底层字节切片的引用,Fiber的响应对象被复用时,后续请求的Body写入会覆盖这个切片的内容,导致缓存的Body数据和实际存储的不一致,比如Content-Length从86927变成46727。 - 锁的释放逻辑隐患:当前代码仅在缓存未命中的分支末尾解锁,若
proxy.Do之后的代码发生panic,会导致Mutex永久锁定,引发服务死锁。
修复方案
修改缓存数据的存储逻辑,对Header和Body进行深拷贝,同时优化锁的释放逻辑:
func call_web(c *fiber.Ctx) error { uri := c.OriginalURL() request_url := lhb_web_url + uri cacheMutex1.Lock() defer cacheMutex1.Unlock() // 用defer确保锁一定会释放 cachedVal, found := caching_value.Get(uri) if !found { if err := proxy.Do(c, request_url); err != nil { return err } // 对Header和Body做深拷贝,避免引用共享 will_caching := &cache_data{ response_header: func() map[string]string { h := make(map[string]string) for k, v := range c.GetRespHeaders() { h[k] = v } return h }(), response_body: append([]byte{}, c.Response().Body()...), } fmt.Println("Data Store!") caching_value.Set(uri, will_caching, cache.DefaultExpiration) asdf, _ := caching_value.Get(uri) fmt.Println(asdf.(*cache_data).response_header) return nil } fmt.Println("Caching!") cachedData := cachedVal.(*cache_data) for k, v := range cachedData.response_header { c.Set(k, v) } c.Response().BodyWriter().Write(cachedData.response_body) return nil }
日志异常对应说明
从测试日志可以看到:
- 第一次缓存存储时,
Content-Length为86927,Content-Type为application/javascript - 第二次读取缓存时,
Content-Length变成46727,Content-Type变成image/jpegn/javascript
这完全符合上下文对象被复用后,新请求的响应数据覆盖缓存引用内容的表现。
内容的提问来源于stack exchange,提问作者HHJ
相关产品推荐
相关产品推荐

