Rocket的目標是提供一個高彈性和高可用性的組態配置系統,開發者或是系統管理員可以很輕易地對每一個別的設定項目使用環境變數、設定檔或是程式碼來進行設定。



以設定優先等級來說,寫死在程式碼內的設定值的優先權是最高的。其次是環境變數,最後才是寫在設定檔中的設定值。這篇文章會先從優先權最低的設定方式開始說明。

不過在開始說明設定方式之前,先來了解一下Rocket框架到底有哪些項目可以設定吧!

Rocket框架的組態配置

啟動Rocket框架時,Rocket會於標準輸出(stdin)中列出啟動該Rocket應用程式時所使用的組態配置。如下圖所示:

rocket-configuration

Rocket框架的主要可設定項目如下表:

項目名稱 類型 預設值(預設會用編譯模式來區分Profile:debug/release) 功用
address 字串(IP位址) 127.0.0.1 Rocket框架啟動時要監聽的網路介面(IP位址)。
port 整數(16位元的無號整數) 8000 Rocket框架啟動時要監聽的TCP連接埠。
workers 整數(無號整數) CPU邏輯核心的數量 執行非同步函數的執行緒數量。
max_blocking 整數(無號整數) 512 執行阻塞任務的最大執行緒數量。
ident 字串、false Rocket 在HTTP回應中,於Server標頭欄位中要夾帶的值。如果設為false,則不回應Server標頭。
ip_header 字串、false X-Real-IP 在HTTP請求中,要把哪個標頭欄位中的值當作是客戶端的真實IP。如果設為false,則不使用這個方式來取得客戶端的真實IP。
limits 表格(欄位的值皆為表示位元組大小的字串) { bytes = "8KiB", data-form = "2MiB", file = "1MiB", form = "32KiB", json = "1MiB", msgpack = "1MiB", string = "8KiB" } 針對不同的請求類型,來限制Rocket框架在讀取每個請求時,最大能讀取前面的幾個位元組。
temp_dir 字串(目錄路徑) 執行環境的暫存目錄 暫存檔所存放的目錄之路徑。
keep_alive 整數(32位元的無號整數,表示秒數) 5 HTTP連線的keep-alive時間,0為不開啟;超過0表示要keep-alive的秒數。
tls 表格(certskey值分別為SSL證書和密鑰的路徑) 使Rocket框架能夠提供HTTPS服務。如果不設定的話就只會使用HTTP。Rocket框架所提供的HTTPS功能不建議使用在正式環境中,應使用Nginx等反向代理伺服器。
secret_key 字串(256位元或是512位元的Base64資料) 由Rocket框架於啟動時隨機產生。 用來作為基於Cookie的會話(Cookie-based Session)等需加密時的場合所使用的密鑰。在使用release執行環境時,這個項目的值必須由系統管理員手動設定,確保每個應用程式實體都是使用一樣的密鑰。這個欄位只會在啟用rocketsecrets特色時才會有作用。
shutdown 表格
(ctrlc為布林值,設定是否能用Ctrl + c來觸發shutdown;
force為布林值,設定是否強制關閉非同步執行環境;
signals為Set集合,設定哪些中斷信號可以觸發shutdown,Unix環境才有效;
gracemercy為32位元無號整數,前者為強制關閉HTTP回應等伺服器I/O前的等待時間秒數,後者為強制關閉連線I/O前的等待時間秒數)
{ ctrlc = true, force = true, signals = [SIGTERM], grace = 2, mercy = 3 } 設定如何「優雅的關機」(Graceful Shutdown)。
log_level 字串(offcriticalnormaldebug) normal/critical 設定Log的輸出層級。愈靠近debug層級的話,輸出的Log愈多。
cli_colors 布林 true 是否在Log中使用顏色和Emoji。

關於secret_key的產生,可以直接使用OpenSSL指令來完成。指令如下:

openssl rand -base64 32

rocket-configuration

設定Rocket框架

用設定檔設定Rocket框架

Rocket框架在啟動的時候,預設會去讀取工作目錄中的Rocket.toml檔案,如果這個檔案不存在,就會不斷地往上層目錄中尋找Rocket.toml檔案來用。

Rocket.toml設定檔的撰寫方式很簡單,如下:

[default]
address = "0.0.0.0"
port = 9958
keep_alive = 0
workers = 32
log = "debug"
secret_key = "nPu3M2/h4UOA8kVEpPqH+4KUzLaJKwhM78BAMBH+AEM="
limits = { form = "10MiB" }

rocket-configuration

default區塊會覆寫掉欄位的預設值。如果想要針對某個Profile來設定的話,可以直接把Profile的名稱作為區塊名稱,寫進Rocket.toml設定檔中。

例如:

[default]
workers = 16
limits = { form = "32KiB" }

[debug]
address = "127.0.0.1"
port = 8000
keep_alive = 5
log = "normal"

[release]
address = "0.0.0.0"
port = 80
keep_alive = 10
log = "off"
secret_key = "nPu3M2/h4UOA8kVEpPqH+4KUzLaJKwhM78BAMBH+AEM="

如果要加入自定義的Profile也是可以,也是一樣將Profile名稱作為區塊名稱來撰寫即可,如下:

[my_profile]
port = 12345
secret_key = "nPu3M2/h4UOA8kVEpPqH+4KUzLaJKwhM78BAMBH+AEM="

使用自定義的Profile時,未定義到的項目預設值會使用debug這個Profile的預設值,請見上表(但secret_key必須要手動設定)。至於要如何讓Rocket套用為這個Profile,會在下一個小節說明。

用環境變數設定Rocket框架

Rocket的設定項目,都可以使用ROCKET_項目名稱(大寫)這樣的環境變數命名方式來設定。

例如:

ROCKET_ADDRESS=0.0.0.0
ROCKET_PORT=9958
ROCKET_WORKERS=16
ROCKET_KEEP_ALIVE=0
ROCKET_LOG_LEVEL=debug
ROCKET_SECRET_KEY='nPu3M2/h4UOA8kVEpPqH+4KUzLaJKwhM78BAMBH+AEM='
ROCKET_LIMITS='{form = "10MiB"}'

rocket-configuration

如果想要更改Profile,則要用ROCKET_PROFILE這個環境變數。

例如以下指令,可以讓Rocket應用程式以my_profile環境來執行:

ROCKET_PROFILE=my_profile cargo run

rocket-configuration

用程式碼來設定Rocket框架

如果我們想要用程式碼來設定Rocket框架的話,程式可以寫成如以下這樣:

#[macro_use]
extern crate rocket;

use rocket::{
    config::{Config, LogLevel},
    data::{Limits, ToByteUnit},
};

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

#[launch]
fn rocket() -> _ {
    let figment = Config::figment()
        .merge(("address", "0.0.0.0"))
        .merge(("port", 9958))
        .merge(("keep_alive", 0))
        .merge(("worker", 16))
        .merge((
            "log_level",
            if cfg!(debug_assertions) { LogLevel::Debug } else { LogLevel::Critical },
        ))
        .merge(("secret_key", "nPu3M2/h4UOA8kVEpPqH+4KUzLaJKwhM78BAMBH+AEM="))
        .merge(("limits", Limits::new().limit("form", 10.mebibytes())));

    rocket::custom(figment).mount("/", routes![index])
}

自訂的項目名稱

Rocket框架的設定檔並不是只能撰寫上述提到的設定項目,如果我們有其它設定值想要透過Rocket框架的設定檔來傳入的話,也是同樣可以用環境變數、設定檔或是程式碼的方式將我們自訂的項目名稱以及設定值傳給Rocket框架。

例如:

[default]
custom = 16384

[release]
custom = 4096
ROCKET_CUSTOM=16384
let figment = Config::figment()
    .merge(("custom", if cfg!(debug_assertions) { 16384 } else { 4096 }));

let rocket = rocket::custom(figment);

...

把設定值傳給Rocket框架之後呢?要怎麼在框架內取得?這個就先留到後面的章節再來介紹啦!現階段我們可以用Figment結構實體提供的extract_inner方法來取得指定的設定欄位,如以下程式:

#[macro_use]
extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

#[launch]
fn rocket() -> _ {
    let figment = rocket::Config::figment()
        .merge(("custom", if cfg!(debug_assertions) { 16384 } else { 4096 }));

    println!("custom = {:?}", figment.extract_inner::<u32>("custom"));

    rocket::custom(figment).mount("/", routes![index])
}

總結

在這個章節中,我們瞭解了Rocket框架的設定方式。直至目前為止,我們所學的Rocket知識已經足夠完成Web應用程式的開發和部署了。不過,Rocket框架的功能遠遠不只有這些。在下一個章節中,我們要來學習Rocket框架提供的錯誤捕獲者機制。

下一章:錯誤捕獲者(Error Catcher)