靜態網站重新發佈時仍維持上線
過去在 Mythex 重新發佈靜態網站時,會先刪除線上的檔案,再上傳新的建置版本,因此在上傳期間,部分訪客會看到 404 頁面,或是缺少腳本的頁面。上傳失敗時,網站甚至可能被清空,或只剩下一半是新的內容。現在,新的建置會直接覆蓋舊的,頁面最後才上傳,殘留的檔案則在幾分鐘後移除。第二項修正讓重新發佈的變更能在幾秒內生效,而不是一分鐘——對於像標誌這類的檔案,過去可能要等上一整天。
靜態網站如何提供服務
靜態網站就是純檔案:HTML 頁面、JavaScript、CSS、圖片。你在 Mythex 發佈時,我們會建置網站、把輸出內容上傳到物件儲存空間中你網站專屬的資料夾,然後透過邊緣網路提供服務——邊緣伺服器位於靠近訪客的位置,會從儲存空間取得檔案,並保留一段時間的副本。(如果你對這個概念還不熟悉,我們的指南 什麼是 CDN 有說明。)
當時有兩件事出了問題:重新發佈時變更檔案的順序,以及舊副本保留的時間。
問題一:上傳時先清空了網站
重新發佈會先刪除網站資料夾中的所有內容,然後才上傳新建置。在上傳進行的這段時間裡(在我們本機測試中,一個 250 個檔案的網站需要 12 秒),若訪客的請求在邊緣尚未快取,就會得到 404,或是一個腳本回傳 404 的 HTML 頁面。
上傳失敗時情況更糟。資料夾已經被清空,而在其中一條上傳路徑上,新的 index.html 可能會先於失敗的那個檔案寫入。一次被回報為失敗的發佈,可能會讓一半新、一半舊的網站上線。
修正方式:覆寫、頁面最後、事後清理
- 不要先刪除。 新建置直接上傳覆蓋在舊的上面。
- 資產先於頁面。 頁面會指明它需要哪些腳本與樣式,因此頁面最後上傳。在新頁面上傳完成前,訪客拿到的是舊頁面,它指向的舊資產仍然存在;新頁面上傳後,它指向的新資產已經就位。
- 稍後移除殘留檔案。 上傳前,我們會先列出網站目前包含的檔案。上傳成功三分鐘後,清單中新建置沒有重寫的檔案會被刪除。三分鐘比頁面在邊緣與瀏覽器中可被快取的 60 秒更長,因此仍持有舊頁面的訪客,能找到該頁面所指向的資產。
- 拿不準就不刪除。 如果上傳前的列舉失敗,就不會進行任何清理。殘留檔案無害,下次發佈時會清除。在不知道裡面有什麼的情況下刪除,正是網站變成空白的原因。
現在,上傳失敗時,先前的網站會完全維持原狀。
我們用真實的上傳腳本、真實的上傳路由與儲存服務,並以冷快取的邊緣訪客,在本機端對此進行了完整測試。使用舊程式碼時,重新發佈期間有 91 次中的 55 次 訪問出現異常;在上傳失敗期間,則有 92 次中的 61 次。使用新程式碼後,在約 3,500 次訪問中,涵蓋兩條上傳路徑、一次失敗的上傳,以及之後的發佈,異常次數為 0,且只有殘留檔案被清除。
問題二:重新發佈的變更顯示太慢
即使上傳順利完成,變更出現得也很慢。邊緣對頁面保留副本 60 秒、對其他所有檔案保留一天,並要求瀏覽器也這樣做。固定名稱的檔案,例如 logo.png、字型,或任何來自 public/ 資料夾的檔案,在重新發佈後可能顯示舊版本長達一天。
修正方式:把檔案副本歸於建置之下
當邊緣向我們的 API 詢問網站位於何處時,回覆現在會包含一個 建置標記,每次發佈生效時都會改變。邊緣會把副本存放在該標記之下。因此,一旦邊緣 30 秒的查詢過期,發佈就會變成一組全新的快取鍵。舊副本再也找不到,因此邊緣可以保留副本一整天,而不會提供被取代的發佈版本之前的內容。
瀏覽器則有兩種不同的規則:
- 雜湊建置輸出——像
assets/index-CzLcxDO8.js這樣的檔案,名稱會隨內容改變——快取一年並標記為 immutable。在該名稱下,它永遠不會過期。 - 其他所有內容——頁面以及固定名稱的檔案,例如標誌——標記為
no-cache,意思是「使用前先確認」。如果沒有變更,回應就是一個很小的304 Not Modified,不帶內容,因為我們現在會尊重瀏覽器的If-None-Match檢查。
區分這兩種檔案需要小心:從 public/assets/ 複製的檔案會保留它自己的名稱,如果把 assets/logo.png 快取一年,就會把舊標誌固定一年。因此,只有當檔案位於建置輸出資料夾 且 其名稱中有一段看起來像雜湊、而非一般單字的片段時,才會被視為雜湊檔案。
在本機測試中,新的頁面與標誌在發佈生效後 6 秒 就能看到。以前頁面需要 60 秒,標誌則需要一天。
另外兩個較小的修正
- HEAD 請求造成空白頁面。
HEAD請求只要求頁面的標頭,不要求內容。我們之前會快取這些空回應,導致下一位訪客看到空白頁面。現在不再快取HEAD回應。 - 「沒有內容」的真正頁面。 指向沒有 App 的位址,以前會回傳純文字的「This published app is offline or the link was not found」,並帶有 502 錯誤碼。現在它會顯示正式的頁面「這裡沒有 App」,狀態碼為 404,並附上回到 Mythex 的連結給擁有者。未知的自訂網域也會顯示同樣的頁面。
我們從中學到什麼
- 順序也是正確性的一部分。 以不同順序上傳相同的檔案,就是網站壞掉與正常運作之間的差別。
- 延後刪除,而且只刪除你知道的內容。 使用上傳前的清單進行清理是安全的;清空資料夾然後寄望上傳能順利完成則不安全。
- 依版本快取,而不是依時間快取。 過期時間是對內容何時改變的猜測。隨建置改變的鍵則是事實。
相關文章:你的已發佈 App 在重新發佈時仍維持上線。更多發佈相關內容請見文件。