[Golang] Go standard library http.FileServer achieve static files

http.FileServer methods belong to the standard library net / http, returns an interface to use FileSystem root to provide file access services HTTP handler. You can easily achieve static file server.

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

Access http://127.0.0.1:8080, you can see something like Nginx in autoindex directory browsing.

Source resolve

We are now above that only one line of code to analyze to see how in the end is achieved. English source code is also more detailed comments, you can refer to.

We look at http.Dir (), look at http.FileServer (), and http.ListenAndServe () listens on TCP port and provides routing services, not repeat them here.

http.Dir ()

We can see from the source, type Dir string implements an interface function of Open type FileSystem interface, http.Dir ( "/") is http.Dir actual return type to convert the string to a file system path.
The using the implements the FileSystem the Dir A // The Native File System Restricted to A
// specific Directory Tree.
//
// The FileSystem.Open Method Takes the While '/' - Separated Paths, the Dir apos String A
// value IS ON A The filename Native System File, not the URL of A, SO IT IS Separated
// by filepath.Separator, Which IS not Necessarily '/'.
//
// Note that the allow Dir by Will Access to Files and Directories Starting with A
// period, Which could Directories like .git A sensitive EXPOSE Directory or
// Files sensitive .htpasswd like. Files with the To the exclude A leading period,
// remove the files/directories from the server or create a custom FileSystem
// implementation.
//
// An empty Dir is treated as “.”.

type Dir string

// A FileSystem implements access to a collection of named files.
// The elements in a file path are separated by slash (’/’, U+002F)
// characters, regardless of host operating system convention.

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

// Open implements FileSystem using os.Open, opening files for reading rooted
// and relative to the directory d.

func (d Dir) Open(name string) (File, error) {
	if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
		return nil, errors.New("http: invalid character in file path")
	}
	dir := string(d)
	if dir == "" {
		dir = "."
	}
	fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
	f, err := os.Open(fullName)
	if err != nil {
		return nil, mapDirOpenError(err, fullName)
	}
	return f, nil
}
http.FileServer()

http.FileServer () method returns fileHandler example, and implements a method fileHandler structure ServeHTTP Handler interface (). The core in ServeHTTP method is serveFile () method.

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

fileHandler definition:

type fileHandler struct {
	root FileSystem
}

fileHandler achieved ServeHTTP (w ResponseWriter, r * Request) method:

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

serveFile () method for determining, if the access path is a directory, to list the contents, if the file is used serveContent (Method output file contents). serveContent () is a method to read the contents of the file and the output method where the code is no longer attached.

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

https://golang.org/src/net/http/fs.go

Published 349 original articles · won praise 14 · views 90000 +

Guess you like

Origin blog.csdn.net/LU_ZHAO/article/details/105304982