Go搭建靜態頁面server筆記

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

go是一門簡潔強大的語言,簡單體驗之後覺得對於網路和命令列的支援也非常棒,本文介紹一下go實現靜態伺服器的大致流程。

基礎實現

最近接手了gobyexample的翻譯工作,將項目重構後需要本地的測試環境。
由於想要頁面的url顯示為“https://gobyexample.xgwang.me/hello-world”這種結尾不帶“/”的形式,子頁面沒有帶上html,並且有圖片資源因此需要一個static server。

根據golang wiki,實現這個簡單server只需要...一行代碼:

package mainimport "net/http"func main() {    panic(http.ListenAndServe(":8080", http.FileServer(http.Dir("/usr/share/doc"))))}

加入log後稍微改寫一下,放在我們項目的tools目錄下:

package mainimport (    "log"    "net/http")func main() {    // Simple static webserver:    port := ":8080"    log.Printf("Serving at: http://localhost%s\n", port)    err := http.ListenAndServe(port, http.FileServer(http.Dir("public")))    if err != nil {        log.Fatal("ListenAndServe fail:", err)    }}

再來一個可執行檔tools/serve檔案

#!/bin/bashexec go run tools/serve.go

ok現在只需要tools/serve就可以啟動這個伺服器了。

404

一切看起來很正常,但如果我們訪問一下不存在的某個頁面,404.html並不會被serve,這是因為go提供的FileServer並不知道我們自訂的404頁面。
所以我們需要將http.FileServer改為一個自訂的Handler

寫go的時候體驗特別好的一點就是go官方團隊提供了很opinionated的convention,比如go-get,go-fmt等。
在我們輸入http.FileServer時會自動在imports中添加相應的庫,跳轉到源碼後看到了這個函數的實現:

type fileHandler struct {    root FileSystem}// FileServer returns a handler that serves HTTP requests// with the contents of the file system rooted at root.//// To use the operating system's file system implementation,// use http.Dir:////     http.Handle("/", http.FileServer(http.Dir("/tmp")))//// As a special case, the returned file server redirects any request// ending in "/index.html" to the same path, without the final// "index.html".func FileServer(root FileSystem) Handler {    return &fileHandler{root}}func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {    upath := r.URL.Path    if !strings.HasPrefix(upath, "/") {        upath = "/" + upath        r.URL.Path = upath    }    serveFile(w, r, f.root, path.Clean(upath), true)}

於是我們知道了這裡的函數需要返回的Handler有一個ServeHTTP方法。但是這裡的serveFile並不能直接由http.serveFile調用:go規定一個package內小寫字母開頭的均為私人,不能被外部package訪問。

但是沒有關係,我們可以在fileHandler上再封裝一層代理,在執行完我們判斷檔案存在的邏輯後執行原先所有fileHandler.ServeHTTP的內容,修改後的代碼如下:

type fileHandler struct {    root http.FileSystem    h    http.Handler}func fileServer(root http.FileSystem, h http.Handler) http.Handler {    return &fileHandler{root, h}}func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {    path := r.URL.Path    if _, err := os.Stat("public/" + path); os.IsNotExist(err) {        http.ServeFile(w, r, "public/404.html")        return    }    f.h.ServeHTTP(w, r)}func main() {    // Simple static webserver:    port := ":8080"    log.Printf("Serving at: http://localhost%s\n", port)    fs := http.Dir("public")    http.Handle("/", fileServer(&fs, http.FileServer(&fs)))    err := http.ListenAndServe(port, nil)    if err != nil {        log.Fatal("ListenAndServe fail:", err)    }}

在傳入FileSystem的時候傳入指標也避免建立,很有C的感覺。

小細節

準系統都已經實現,但作為一個命令列工具,希望再進行一些完善。

首先我們需要支援傳參,go對於命令列參數的支援非常棒,只要引入builtin的flag包之後,我們加入

port := flag.String("port", ":8080", "localhost port to serve")path := flag.String("path", "public", "public files path")flag.Parse()

就可以得到*string類型的命令列參數,並且天生支援預設值和描述,測試一下go run tools/serve.go -h,可以得到:

Usage of /var/folders/sd/cwk5fwtd4ms5vflhq5_0_5rr0000gn/T/go-build178666598/command-line-arguments/_obj/exe/serve:  -path string        public files path (default "public")  -port string        localhost port to serve (default ":8080")

準備serve檔案之前,再輸出一下帶有格式的資訊加粗一下我們傳入的參數:

log.Printf("Serving \x1b[1m%s\x1b[0m at: http://localhost\x1b[1m%s\x1b[0m\n", *path, *port)

這裡\x1b[0m代表“All attributes off(color at startup)”,\x1b[1m代表“Bold on(enable foreground intensity)”。

總結

go作為靜態語言擁有可以與動態語言媲美的靈活性,有完整易用的工具鏈和豐富的標準庫,是2017年增長最快的語言,簡單的同時非常強大。
希望有更多的人可以一起學習go,我正在完善Go By Example的翻譯,歡迎閱讀以及貢獻PR!

閱讀原文

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.