Go 標準庫 http-FileServer 實現靜態文件服務

【導讀】go 項目想做文件上傳怎麼做?本文介紹了用 http.FileServer 實現靜態文件服務器的操作。

http.FileServer 方法屬於標準庫 net/http,返回一個使用 FileSystem 接口 root 提供文件訪問服務的 HTTP 處理器。可以方便的實現靜態文件服務器。

http.ListenAndServe(":8080", http.FileServer(http.Dir("/files/path")))

訪問 http://127.0.0.1:8080,即可看到類似 Nginx 中 autoindex 目錄瀏覽功能。

源碼解析

我們現在開始將上述的那僅有的一行代碼進行剖析,看看到底是如何實現的。源碼中英文註釋也比較詳細,可以參考。

我們先看 http.Dir(),再看 http.FileServer(),而 http.ListenAndServe() 監聽 TCP 端口並提供路由服務,此處不贅述。

http.Dir()

從以下源碼我們可以看出,type Dir string 實現了 type FileSystem interface 的接口函數 Openhttp.Dir("/") 實際返回的是 http.Dir 類型,將字符串路徑轉換成文件系統。

// 所屬文件: src/net/http/fs.go, 26-87行

type Dir string

func (d Dir) Open(name string) (File, error) {
 // ...
}

type FileSystem interface {
 Open(name string) (File, error)
}

http.FileServer()

http.FileServer() 方法返回的是 fileHandler 實例,而 fileHandler 結構體實現了 Handler 接口的方法 ServeHTTP()ServeHTTP 方法內的核心是 serveFile() 方法。

// 所屬文件: src/net/http/fs.go, 690-716行

type fileHandler struct {
 root FileSystem
}

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)
}
// 所屬文件: src/net/http/server.go, 82行

type Handler interface {
 ServeHTTP(ResponseWriter, *Request)
}

serveFile() 方法判斷,如果訪問路徑是目錄,則列出目錄內容,如果是文件則使用 serveContent() 方法輸出文件內容。serveContent() 方法則是個讀取文件內容並輸出的方法,此處不再貼代碼。

// 所屬文件: src/net/http/fs.go, 540行

// name is '/'-separated, not filepath.Separator.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {

   // 中間代碼已省略

   if d.IsDir() {
    if checkIfModifiedSince(r, d.ModTime()) == condFalse {
     writeNotModified(w)
     return
    }
    w.Header().Set("Last-Modified", d.ModTime().UTC().Format(TimeFormat))
    dirList(w, r, f)
    return
   }

   // serveContent will check modification time
   sizeFunc := func() (int64, error) { return d.Size(), nil }
   serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
}

支持子目錄路徑

http.StripPrefix() 方法配合 http.Handle()http.HandleFunc() 可以實現帶路由前綴的文件服務。

package main

import (
    "net/http"
    "fmt"
)

func main() {

    http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))

    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println(err)
    }

}

轉自:

shockerli.net/post/golang-pkg-http-file-server/

Go 開發大全

參與維護一個非常全面的 Go 開源技術資源庫。日常分享 Go, 雲原生、k8s、Docker 和微服務方面的技術文章和行業動態。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/B-eCIueOyIBE3K0boDeHqA