今天是第十天,今天完成整個鐵人賽就完成三分之一!告訴自己要繼續堅持努力下去。
今天會介紹的go伺服器應用範例是靜態檔案分享伺服器(File System Server),可能有人會想這種東西有什麼好獨立成一台Web Server,其實這關係到近來一個逐漸流行的網路框架設計概念,我們先來聊聊什麼是「微服務」:
我第一次聽到這個名詞其實是在今年初的某次面試時,幸好我當時就字面上理解的並沒有什麼差異。過去的網站不管有多少功能,都會視為一個專案,部署時自然也會整包部署。就算有自動擴展或附載平衡,也都是以整個專案為一個單位考量,但這樣其實喪失了一些靈活性。
想像一個情境:一個線上商城的專案,把會員的部分獨立一個伺服器、結帳獨立一個伺服器、商品管理獨立一個伺服器、前端頁面UI獨立一個伺服器。把原本全都綑綁在同一個專案中的各個功能解耦合,降低相依性,彼此之間用API互相溝通,這樣可以有什麼好處?
原本是一個巨大的專案,如果有週年慶等大型活動,動態加到兩百台虛擬主機,其中所有功能都等比例提升,但實際上並不是所有部分都有相同需求;拆散之後,商品管理在大型活動之前壓力不變、會員系統微微提升,最終可以把所有資源投注在頁面與結帳,資源使用更有效率!
拆為獨立的伺服器之後,各功能之間勢必要將原本錯綜複雜的邏輯解除開,彼此只處理自己的部分,清爽乾淨更不容易產生架構問題。如果要導入新技術,各伺服器分別升級的風險,也比一次動整包來得更安全。
當商城越做越大,可能書店的部分獨立為一個事業群,另外又開始活動報名等新的業務,如果沒有將功能切開,與商城綑綁在一起的會員與結帳難以支援其他服務;如果是分別的伺服器,只要符合API規格,擴展性更高。書店、活動報名等可以使用相同的會員、結帳API,更換前端、商品管理即可。
事實上這樣的概念在python的網路框架Django中就有設計出來,雖然還是包在同一個專案內,但各功能之間保持高度的獨立性,有關這部分可以參考我去年鐵人賽的文章Django與Rails比較。
前面說了這麼多,我們馬上來看看code範例:
package main
import (
"net/http"
)
func ping(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("pong"))
}
func main() {
http.Handle("/", http.FileServer(http.Dir("./src")))
http.HandleFunc("/ping", ping)
if err := http.ListenAndServe(":8000", nil); err != nil {
panic(err)
}
}
然後在根目錄下建一個src
的資料夾,在裡面放靜態檔案。接著將伺服器啟動,訪問同名的路徑,就可以找到我們剛剛放的檔案囉!我們可以觀察一下今天的範例與前幾天有一些不同之處:
http.HandleFunc
對應到別的方法(在這個例子中對應到ping()
);新的http.Handle
後面則直接將http.FileServer
作為參數,連結到靜態檔案。http.ListenAndServe
監聽路由依然是必備的句子,但今天他不是獨立存在,而是寫在條件判斷內,給值的同時做錯誤處理。這樣的句型結構是前面幾天講到的,在go之中最接近三元運算子(ternary conditional operator)的寫法,可以當作比較進階的go句型使用。 http.Handle("/", http.FileServer(http.Dir("./src")))
http.HandleFunc("/apple.jpg", ping) // 與靜態資源同名
則會以HandleFunc
為優先,也就是說會導引導ping
而不是顯示靜態資源,這個部分需要特別注意!