欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

解析Go 标准库 http.FileServer 实现静态文件服务

程序员文章站 2022-03-20 15:17:46
http.fileserver 方法属于标准库 net/http,返回一个使用 filesystem 接口 root 提供文件访问服务的 http 处理器。可以方便的实现静...

http.fileserver 方法属于标准库 net/http,返回一个使用 filesystem 接口 root 提供文件访问服务的 http 处理器。可以方便的实现静态文件服务器。

http.listenandserve(":8080", http.fileserver(http.dir("/files/path")))

访问 ,即可看到类似 nginx 中 autoindex 目录浏览功能。

源码解析

我们现在开始将上述的那仅有的一行代码进行剖析,看看到底是如何实现的。源码中英文注释也比较详细,可以参考。

我们先看 http.dir(),再看 http.fileserver(),而 http.listenandserve() 监听 tcp 端口并提供路由服务,此处不赘述。

http.dir()

从以下源码我们可以看出,type dir string 实现了 type filesystem interface 的接口函数 open,http.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)
  }
}

总结

以上所述是小编给大家介绍的解析go 标准库 http.fileserver 实现静态文件服务,希望对大家有所帮助