在先前的文章中有提到用Rocket框架回應任意資料的方式,在另一篇文章中也有介紹用Rocket框架來實現HTTP的ETag快取機制,要怎麼樣把這兩個東西結合在一起使用呢?



Etagged Raw Response for Rocket Framework

「Etagged Raw Response for Rocket Framework」是筆者開發的套件,可以使Rocket框架依據HTTP請求的If-None-Match標頭欄位來判斷是否要直接回應一個Vec<u8>實體、一個Reader或是一個檔案,並且快速地替其加入Content-Type標頭和ETag欄位。

Crates.io

https://crates.io/crates/rocket-etagged-raw-response

Cargo.toml

rocket-etagged-raw-response = "*"

使用方法

rocket_etagged_raw_response這個crate提供的EtaggedRawResponse結構體可以當作要回應的資料型別。EtaggedRawResponse結構體提供了from_static關聯函數和from_vec關聯函數,可以從參數中傳入要拿來回應的&'static [u8]參考或Vec<u8>實體、檔案類型和開啟時預設的檔案名稱(如果不設定檔案名稱的話,網頁瀏覽器會用網址路徑的檔案名稱來當作檔案名稱)。它也提供了from_reader關聯函數,可以從參數中傳入任意有實作Read特性的實體、檔案類型和開啟時預設的檔案名稱。

如果資料來源為檔案的話,那就更方便了,可以直接使用EtaggedRawResponse結構體提供的from_file關聯函數,可以從參數中傳入檔案路徑、檔案類型和開啟時預設的檔案名稱。如果不提供檔案類型的話,預設會由檔案路徑中的副檔名來判斷;如果不提供檔案名稱的話,預設會由檔案路徑中的檔案名稱來判斷;如果想要直接使用網址路徑的檔案名稱作為預設的檔案名稱的話,那就把檔案名稱設定為空字串。

舉個例子,假設工作目錄中有image.jpg這張JPEG圖檔。若想要讓Rocket框架提供這個圖檔,並且讓網頁瀏覽器直接瀏覽這個圖檔,而不是將其下載到檔案系統,然後又要支援ETag機制的話,程式可以這樣寫:

#[macro_use]
extern crate rocket;

use std::io::ErrorKind;
use std::path::Path;

use rocket::http::Status;

use rocket_etagged_raw_response::{EtagIfNoneMatch, EtaggedRawResponse};

#[get("/")]
async fn view(etag_if_none_match: EtagIfNoneMatch<'_>) -> Result<EtaggedRawResponse<'_>, Status> {
    let path = Path::join(Path::new("examples"), Path::join(Path::new("images"), "image(貓).jpg"));

    EtaggedRawResponse::from_file(&etag_if_none_match, path, None::<String>, None).await.map_err(
        |err| {
            if err.kind() == ErrorKind::NotFound {
                Status::NotFound
            } else {
                Status::InternalServerError
            }
        },
    )
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![view])
}