問題描述
先說背景。網站是用PHP開發的,未用任何框架,代碼結構也非常簡單。運行於阿里雲服務器,並采用其CDN來做分發。根據業務需求,有的頁面會判斷用戶瀏覽器類型,依此來選擇PC或者手機端內容。
在一次上線過程中,遇到比較詭異的問題:用PC和手機分別訪問頁面時,網頁內容未根據瀏覽器類型來區分。而在開發環境,頁面卻能正常顯示。仔細排查了代碼,沒有發現問題出在什么地方。而線上環境也不好調試,只能靠猜了。

解決過程
開發環境一切正常,說明代碼出問題的可能性不大(當然后面發現還是代碼的問題~)。而線上與開發環境的差別就在於多了一層CDN。會不會是CDN的問題?然而本人對CDN也是一知半解的,只知道是它會緩存源網站內容,並就近對用戶進行內容分發,來加速訪問。如果用戶請求的內容CDN並未緩存,就會發生回源。對圖片、css、js等靜態資源,CDN緩存是理所應當的。但是對html內容,因為一般都是PHP動態生成的,會有一些業務邏輯,緩存這些內容就不太合適了。由於相關判斷瀏覽器類型的代碼是經過驗證的,所以問題應該不在網站本身。考慮到上面CDN相關內容,我就在懷疑是不是CDN把html都緩存下來了,導致用戶請求壓根沒到網站服務器。於是打開瀏覽器console,查看請求響應頭,並把問題頁的響應頭和正常頁面進行對比,果然發現了問題。正常頁面每次刷新后,響應頭里的Date字段都會改變;而問題頁的Date字段一直沒變化!也就是說問題頁取到的內容一直都是CDN緩存。再次對比發現,正常頁面還有Cache-Control相關內容,而問題頁沒有。於是推測CDN會根據響應頭來決定是否會緩存內容。在問題頁代碼中增加緩存控制相關header后,果然正常了。然而問題又來了,正常頁面的Cache-Control是哪里輸出的呢?代碼中並沒有看到對應內容,估計是線上人為加了相關header,與開發環境代碼不一致。
總結
一直以來對http響應頭中的緩存控制相關內容都沒有注意,遇到問題才發現它們的重要性。本次解決這個問題,主要是增加了以下header:
header('Pragma: no-cache');//兼容老版本協議 http1.0可能不識別Cache-Control
header('Cache-Control: no-store, no-cache, must-revalidate');//告訴瀏覽器/代理 不緩存內容
header("Expires: Mon, 26 Jul 1970 05:00:00 GMT"); //把過期時間設置為以往的時間,基本等同於Cache-Control:no-cache
頁面加上三行代碼后基本可保證其內容不被緩存。
阿里雲CDN響應頭中有幾個關於緩存的字段需要注意:
X-Cache,值包含HIT時,表示命中緩存;MISS則表示未命中,需要回源
X-Swift-SaveTime 緩存保存時間
X-Swift-CacheTime 緩存時長
Age 當前資源已緩存的時間,達到X-Swift-CacheTime時緩存過期,會回源
想了解更多HTTP協議相關內容,請查看HTTP協議簡介