http.FileServer
方法屬於標準庫net/http
,返回一個使用 FileSystem 接口 root 提供文件訪問服務的 HTTP 處理器。能夠方便的實現靜態文件服務器。
http.ListenAndServe(":8080", http.FileServer(http.Dir("/files/path")))
訪問 http://127.0.0.1:8080
,便可看到相似 Nginx 中 autoindex
目錄瀏覽功能。golang
咱們如今開始將上述的那僅有的一行代碼進行剖析,看看究竟是如何實現的。源碼中英文註釋也比較詳細,能夠參考。服務器
咱們先看 http.Dir()
,再看 http.FileServer()
,而 http.ListenAndServe()
監聽 TCP 端口並提供路由服務,此處不贅述。函數
從如下源碼咱們能夠看出,type Dir string
實現了 type FileSystem interface
的接口函數 Open
,http.Dir("/")
實際返回的是 http.Dir
類型,將字符串路徑轉換成文件系統。post
// 所屬文件: 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()
方法返回的是 fileHandler
實例,而 fileHandler
結構體實現了 Handler
接口的方法 ServeHTTP()
。ServeHTTP
方法內的核心是 serveFile()
方法。.net
// 所屬文件: 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()
方法則是個讀取文件內容並輸出的方法,此處再也不貼代碼。code
// 所屬文件: 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()
能夠實現帶路由前綴的文件服務。orm
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) } }
原文地址: https://shockerli.net/post/go...
更多文章請訪問個人我的博客: https://shockerli.net