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

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

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

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

访问 http://127.0.0.1:8080,即可看到类似 Nginx 中 autoindex 目录浏览功能。

源码解析

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

我们先看 http.Dir(),再看 http.FileServer(),而 http.ListenAndServe() 监听 TCP 端口并提供路由服务,此处不赘述。

http.Dir()

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

}

原文地址: https://shockerli.net/post/golang-pkg-http-file-server/


目录
相关文章
|
26天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
41 2
|
24天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
26 2
|
24天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
34 2
|
10天前
|
存储 Go 索引
go语言使用for循环遍历
go语言使用for循环遍历
24 7
|
10天前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。
|
13天前
|
存储 Go
go语言 遍历映射(map)
go语言 遍历映射(map)
26 2
|
14天前
|
Go 调度 开发者
Go语言中的并发编程:深入理解goroutines和channels####
本文旨在探讨Go语言中并发编程的核心概念——goroutines和channels。通过分析它们的工作原理、使用场景以及最佳实践,帮助开发者更好地理解和运用这两种强大的工具来构建高效、可扩展的应用程序。文章还将涵盖一些常见的陷阱和解决方案,以确保在实际应用中能够避免潜在的问题。 ####
|
14天前
|
测试技术 Go 索引
go语言使用 range 关键字遍历
go语言使用 range 关键字遍历
17 3
|
14天前
|
测试技术 Go 索引
go语言通过 for 循环遍历
go语言通过 for 循环遍历
24 3