HTTP協定提供了一些快取機制,最基本的就是Cache-Control。Cache-Control可以用來控制HTTP連線要如何被快取,例如最常見的用法就是透過max-age參數來設定快取時間,搭配public或是private參數來控制快取的可見程度。不過Rocket框架本身並沒有對Cache-Control提供直接的支援,所以使用起來不是很方便。



Cache Response for Rocket Framework

「Cache Response for Rocket Framework」是筆者開發的套件,可以快速地替Rocket的HTTP回應加上Cache-Control機制。

Crates.io

https://crates.io/crates/rocket-cache-response

Cargo.toml

rocket-cache-response = "*"

使用方法

rocket_cache_response這個crate提供了CacheResponse列舉,可以用來包裹任意的HTTP回應的型別,在HTTP回應中加上Cache-Control欄位來進行快取的控制。CacheResponse列舉提供的變體有以下幾種:

  • Public:可以使所有(包括代理伺服器和CDN)的客戶端快取HTTP回應一段時間,在快取的有效時間中,客戶端不需要再向伺服器端重新發送HTTP請求。must_revalidate參數可以用來控制過期的快取是否一定要再向伺服器端重新發送HTTP請求來驗證快取的有效性(驗證的方式可以是在HTTP標頭中夾帶其它的欄位資訊,讓伺服器可以去檢查),當伺服器回傳的HTTP狀態碼為304(Not Modified),表示同意客戶端繼續使用快取,快取時間會重新計算。(一般的網頁瀏覽器不論有無must_revalidate參數都會當作是有must_revalidate參數來處理,但是代理伺服器和CDN就不一定了。)
  • Private:可以使最終客戶端(如網頁瀏覽器)快取HTTP回應一段時間,在快取的有效時間中,客戶端不需要再向伺服器端重新發送HTTP請求。
  • NoCache:允許所有客戶端快取HTTP回應,但每次使用快取時,客戶端都要向伺服器驗證快取的有效性,當伺服器回傳的HTTP狀態碼為304(Not Modified),表示同意客戶端繼續使用快取。如果HTTP回應中沒有Cache-Control欄位,通常就會被當作是NoCache(no-cache)。
  • NoStore:不允許所有客戶端快取HTTP回應。
  • NoCacheControl:不設定(改變)Cache-Control欄位。

以下是一個使用範例:

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate rocket;

extern crate rocket_cache_response;

extern crate chrono;

use rocket_cache_response::CacheResponse;

use chrono::prelude::*;

#[get("/")]
fn index() -> CacheResponse<String> {
    CacheResponse::Public {
        responder: format!("Current Time: {}\n\nTry to re-open this page repeatedly without pressing the refresh(F5) or forced-refresh(Ctrl+F5) buttons.", Utc::now().to_rfc3339()),
        max_age: 10, // cached for seconds
        must_revalidate: false,
    }
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}

另外,CacheResponse列舉還提供public_only_releaseprivate_only_release這兩個關聯函數,可以用來設定只在使用release模式來編譯程式時才使用Public或是Private變體,否則就不設定Cache-Control欄位(NoCacheControl)。避免在程式開發階段,因為有用快取機制而導致一些麻煩的產生。