Parse Go standard library ES1en.FileServer to implement static file service

  • 2020-06-15 09:15:51
  • OfStack

The http. FileServer method belongs to the standard library net/http and returns an HTTP processor that provides file access services using the FileSystem interface root. Static file server can be easily implemented.

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

Visit http://127.0.0.1:8080 to see autoindex directory browsing similar to Nginx.

The source code parsing

Let's now go through the 1 line above and see how it works. Source in English and Chinese annotations are more detailed, you can refer to.

Let's look at http. Dir(), then http. FileServer(), and http.ListenAndServe() Listens on TCP port and provides routing services, which will not be described here.

http.Dir()

From the following source code we can see that type Dir string implements type FileSystem interface's interface function Open, http.Dir ("/") actually returns the http.Dir type to convert the string path to the file system.


//  Belongs to the file : src/net/http/fs.go, 26-87 line 
type Dir string
func (d Dir) Open(name string) (File, error) {
  // ...
}
type FileSystem interface {
  Open(name string) (File, error)
}
http.FileServer()
http.FileServer()  Method returns  fileHandler  Instance,  fileHandler  The structure is implemented  Handler  Methods of interfaces  ServeHTTP() . ServeHTTP  The core of the method is  serveFile()  Methods. 
//  Belongs to the file : src/net/http/fs.go, 690-716 line 
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)
}
//  Belongs to the file : src/net/http/server.go, 82 line 
type Handler interface {
  ServeHTTP(ResponseWriter, *Request)
}

serveFile() Method to list the contents of a directory if the access path is a directory, or a file serveContent() Method outputs the file contents. serveContent() Method is a method that reads the contents of the file and outputs it. No more code is posted here.


//  Belongs to the file : src/net/http/fs.go, 540 line 
// name is '/'-separated, not filepath.Separator.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
  //  The intermediate code has been omitted 
  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)
}

Subdirectory paths are supported

http.StripPrefix() Methods with http.Handle() or http.HandleFunc() You can implement a routing file service with a prefix.


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)
  }
}

conclusion


Related articles: