• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Golang HTTP Fileserver

武飞扬头像
zhanglehes
帮助1

概要

fileserver是静态文件服务,其主要功能是根据提供文件查询与文件传输的功能。由golang标准库提供。

入口函数

  1.  
    func FileServer(root FileSystem) Handler {
  2.  
    return &fileHandler{root}
  3.  
    }
  4.  
     
  5.  
    type fileHandler struct {
  6.  
    root FileSystem
  7.  
    }

它的入参是一个带有根路径的文件系统,返回值是一个http_handler(处理函数)

FileSystem文件系统,支持访问文件路径,无论使用何种操作系统,文件路径通过‘/’进行分隔

  1.  
    type FileSystem interface {
  2.  
    Open(name string) (File, error) // 打开一个文件
  3.  
    }
  4.  
     
  5.  
    type File interface {
  6.  
    io.Closer // 关闭文件
  7.  
    io.Reader // 读文件
  8.  
    io.Seeker // 文件位置信息
  9.  
    Readdir(count int) ([]os.FileInfo, error) // 读文件夹
  10.  
    Stat() (os.FileInfo, error) // 文件状态
  11.  
    }

处理函数

  1.  
    func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
  2.  
    upath := r.URL.Path
  3.  
    if !strings.HasPrefix(upath, "/") { // 改写path
  4.  
    upath = "/" upath
  5.  
    r.URL.Path = upath
  6.  
    }
  7.  
    serveFile(w, r, f.root, path.Clean(upath), true) // 核心逻辑
  8.  
    }
  9.  
     
  10.  
    func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
  11.  
    f, err := fs.Open(name) // 打开文件,全路径是由root name
  12.  
    d, err := f.Stat()
  13.  
    if d.IsDir() { // 如果path指向的是文件夹
  14.  
    if checkIfModifiedSince(r, d.ModTime()) == condFalse { // 判断文件夹是否更新
  15.  
    writeNotModified(w)
  16.  
    return
  17.  
    }
  18.  
    setLastModified(w, d.ModTime()) // 写入文件夹更新时间
  19.  
    dirList(w, r, f) // 见后
  20.  
    return
  21.  
    }
  22.  
     
  23.  
    // 如果path指向的是文件
  24.  
    sizeFunc := func() (int64, error) { return d.Size(), nil }
  25.  
    serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f) // 这部分代码比较复杂,起主要逻辑是通过request中的range信息,多线程读取文件内容,返回写入response中。从中我们可以看到静态服务器是支持断点续传的http服务
  26.  
    }
学新通

文件夹列表

  1.  
    func dirList(w ResponseWriter, r *Request, f File) {
  2.  
    dirs, err := f.Readdir(-1) // 读文件夹
  3.  
    sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() }) // 按照文件名进行排序
  4.  
    // 写html格式的response
  5.  
    w.Header().Set("Content-Type", "text/html; charset=utf-8")
  6.  
    fmt.Fprintf(w, "<pre>\n")
  7.  
    for _, d := range dirs {
  8.  
    name := d.Name()
  9.  
    if d.IsDir() { // 如果是子目录
  10.  
    name = "/"
  11.  
    }
  12.  
    url := url.URL{Path: name}
  13.  
    fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", url.String(), htmlReplacer.Replace(name))
  14.  
    }
  15.  
    fmt.Fprintf(w, "</pre>\n")
  16.  
    }
学新通

用于将字符串路径转换为文件系统

主要的功能是兼容不同的os

定义

type Dir string
  1.  
    // name是当前os的文件路径格式
  2.  
    func (d Dir) Open(name string) (File, error) {
  3.  
    dir := string(d) // 根目录
  4.  
    if dir == "" {
  5.  
    dir = "."
  6.  
    }
  7.  
    fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/" name))) // 拼出全路径
  8.  
    f, err := os.Open(fullName)
  9.  
    if err != nil {
  10.  
    return nil, mapDirOpenError(err, fullName)
  11.  
    }
  12.  
    return f, nil
  13.  
    }

辅助中间件

  1.  
    // 该函数对象改写request的path,是一个中间件
  2.  
    func StripPrefix(prefix string, h Handler) Handler {
  3.  
    if prefix == "" {
  4.  
    return h
  5.  
    }
  6.  
    return HandlerFunc(func(w ResponseWriter, r *Request) { // 其定义见后
  7.  
    if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) { // 前缀匹配
  8.  
    r2 := new(Request) // 创建一个新的request
  9.  
    *r2 = *r
  10.  
    r2.URL = new(url.URL)
  11.  
    *r2.URL = *r.URL
  12.  
    r2.URL.Path = p // 改写path
  13.  
    h.ServeHTTP(w, r2) // 调用hander的处理逻辑
  14.  
    } else {
  15.  
    NotFound(w, r)
  16.  
    }
  17.  
    })
  18.  
    }
  19.  
     
  20.  
    type HandlerFunc func(ResponseWriter, *Request) // 定义一个函数对象
  21.  
     
  22.  
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { // 该函数对象的ServeHTTP方法是执行自身
  23.  
    f(w, r)
  24.  
    }
学新通

put it together

http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))


 

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfbich
系列文章
更多 icon
同类精品
更多 icon
继续加载