在圖靈社群實現快取他人頭像,而對本人不快取
在圖靈社群的開發中有這樣一個情況:
會員的頭像有三種大小,由於檔案都很小,就選擇存在資料庫中了。每個頁面有大量的 GetAvatar(id, size) 請求,對應於 http://www.ituring.com.cn/users/getavatar/82554?size=small,根據會員Id和要求的尺寸這兩個引數,返回的相應的頭像檔案。
頭像很少變化,並且某個人的頭像換了,其他的人晚一點看到新頭像,不影響使用,因此可以使用快取。但是如果某個會員自己重新上傳了頭像,那麼必然要求能立刻看到新頭像,而不能等到若干小時之後快取更新以後才看到,這是一個必須的約束條件。
此外,這個快取要同時考慮 Server 端快取和 Browser 端的快取。
這裡要說明的主要是基於在 ASP.NET 框架本身的實現基於使用者的差異快取的方法,並不是討論這樣處理一個網站的頭像檔案儲存應該怎麼做更好的問題。這裡僅用頭像儲存作為一個具體的案例。
Step 1
在 GetAvatar() 方法上使用 OutputCacheAttribute 特性,並指定快取的時間為 1 天:
[OutputCache(Duration= 3600*24)]
public ActionResult GetAvatar(int id, AvatarSize size)
{
// 省略
}
Step 2
Step 1 中實現了基本的快取功能,同時在 Server 和 Browser 端都有效。但是問題在於,如果一個會員在其個人空間更新了頭像,那麼他也要等到下次更新的時候才能看到新頭像。因此使用OutputCacheAtribute的VaryByCustom引數:
[OutputCache(Duration= 3600*24, VaryByCustom="getAvatar")]
public ActionResult GetAvatar(int id, AvatarSize size)
{
// 省略
}
並在 Global.asax.cs 中重寫 GetVaryByCustomString:
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg == "getAvatar")
{
var id = context.Request.Cookies["iTuringUserId"];
return id != null && id.Value == Request.Path.Split('/')[3]
? DateTime.Now.Ticks.ToString()
: context.Request.Path.Split('/')[3] + Request.Params["size"];
}
return base.GetVaryByCustomString(context, arg);
}
這個函式在呼叫 GetAvatar() 方法之前呼叫,OutputCacheAttribute 會根據你返回的值決定快取的版本。因此,在這個函式中,將請求的 cookies 中的會員的 Id 和所請求的頭像的 Id 進行比較,如果相同說明是本人的請求,則返回一個隨機數(這裡用時間,效果一樣),這樣每次返回這個值都是新值。因此就會取得新的頭像。如果不同,就返回Id和尺寸的組合,這樣就可以使用快取的版本了。
Step 3
Step 2 中已經可以實現根據會員來決定是否使用快取的頭像,但是剩下的問題是,對於本人的請求,第一次返回的時候,設定了 Browser 上的快取,這個快取設定是統一的,都是1天,這樣會導致某個頭像的本人瀏覽頁面時,由於瀏覽器上設定了快取,而根本不會像伺服器發出請求,從而無法得到新的頭像。
因此需要在返回頭像檔案的時候,根據使用者來決定是否設定HTTP頭的快取:
[OutputCache(Duration= 3600*24, VaryByCustom="getAvatar")]
public ActionResult GetAvatar(int id, AvatarSize size)
{
if (Request.Cookies["iTuringUserId"] != null
&& Request.Cookies["iTuringUserId"].Value == id.ToString())
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
// 省略
}
好了,大功告成!
這樣的結果是,顯示非本人頭像的請求的CPU時間降到了0.1ms,而如果直接從資料庫取出並返回,則需要 50~100ms 。而圖靈社群上,很多頁面都要顯示幾十個頭像,因此這個優化還是很有價值的。
此外,這裡的方法具有通用性,能夠實現針對使用者輸出不同的快取版本。
相關文章
- 擷取圖片生成頭像外掛
- SpringBoot快取管理(二) 整合Redis快取實現Spring Boot快取Redis
- 使用ConcurrentHashMap實現快取HashMap快取
- 使用RxJava實現快取RxJava快取
- WebRTC從攝像頭獲取圖片傳入canvasWebCanvas
- vue怎麼設定html不快取 但是js、css等檔案做快取VueHTML快取JSCSS
- Vue專案全域性配置頁面快取,實現按需讀取快取Vue快取
- 對於前端快取的理解(快取機制和快取型別)前端快取型別
- 在 WPF 客戶端實現 AOP 和介面快取客戶端快取
- 實現AVPlayer離線快取快取
- CefSharp自定義快取實現快取
- 快取 LRU 和 LFU 實現快取
- Go中實現Sieve快取Go快取
- Laravel 實現二級快取 提高快取的命中率和細粒化快取 keyLaravel快取
- WEB 應用快取解析以及使用 Redis 實現分散式快取Web快取Redis分散式
- QQ群頭像 微信群頭像 多圖合併框架實現框架
- laravel利用Redis來實現網站快取讀取LaravelRedis網站快取
- Python基於opencv呼叫攝像頭獲取個人圖片PythonOpenCV
- Lfu快取在Rust中的實現及原始碼解析快取Rust原始碼
- 微信小程式 實現網路圖片本地快取微信小程式快取
- offscreenCanvas+worker+IndexedDB實現無感大量圖片快取CanvasIndex快取
- 圖解HTTP快取圖解HTTP快取
- 圖解 HTTP 快取圖解HTTP快取
- SpringBoot中使用Redis實現快取Spring BootRedis快取
- SpringBoot中實現兩級快取Spring Boot快取
- LRU cache快取簡單實現快取
- 【SpringBoot】結合Redis實現快取Spring BootRedis快取
- MUI呼叫原生自定義方法實現計算快取與清空快取UI快取
- 快取穿透、快取擊穿、快取雪崩、快取預熱快取穿透
- 如何防止他人竊取我的原始碼或圖片?原始碼
- 如何實現應用快取?說說你對manifest的理解快取
- 快取穿透、快取擊穿、快取雪崩快取穿透
- 快取穿透、快取雪崩、快取擊穿快取穿透
- 在Kubernetes上使用Spring Boot實現Hazelcast分散式快取 – PiotrSpring BootAST分散式快取
- TP開發的 HTML5頭像擷取案例,會員頭像功能HTML
- 利用localstorage實現本地訊息快取快取
- JavaScript隨機數實現防止快取JavaScript隨機快取
- Spring @cacheable註解實現的快取Spring快取
- MySQL與Redis實現二級快取MySqlRedis快取