http.FileServer 方法屬于標準庫 net/http,返回一個使用 FileSystem 接口 root 提供文件訪問服務的 HTTP 處理器。可以方便的實現(xiàn)靜態(tài)文件服務器。
http.ListenAndServe(":8080", http.FileServer(http.Dir("/files/path")))
訪問 http://127.0.0.1:8080,即可看到類似 Nginx 中 autoindex 目錄瀏覽功能。
源碼解析
我們現(xiàn)在開始將上述的那僅有的一行代碼進行剖析,看看到底是如何實現(xiàn)的。源碼中英文注釋也比較詳細,可以參考。
我們先看 http.Dir(),再看 http.FileServer(),而 http.ListenAndServe()
監(jiān)聽 TCP 端口并提供路由服務,此處不贅述。
http.Dir()
從以下源碼我們可以看出,type Dir string 實現(xiàn)了 type FileSystem interface 的接口函數(shù) Open,http.Dir("/") 實際返回的是 http.Dir 類型,將字符串路徑轉換成文件系統(tǒng)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
// 所屬文件: 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 結構體實現(xiàn)了 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()
方法則是個讀取文件內容并輸出的方法,此處不再貼代碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 所屬文件: 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()
可以實現(xiàn)帶路由前綴的文件服務。
1
2
3
4
5
6
7
8
9
10
11
12
|
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) } } |
總結
以上所述是小編給大家介紹的解析Go 標準庫 http.FileServer 實現(xiàn)靜態(tài)文件服務,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網(wǎng)站的支持!
原文鏈接:https://www.cnblogs.com/shockerli/archive/2018/08/21/golang-pkg-http-file-server.html