Golang web项目中提供静态文件使用,可以用自带的http.FileServer
。
Sample Code
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", home)
...
fileServer := http.FileServer(http.Dir("./ui/static/"))
// 所有以/static/开头的url,都会被以下handler处理。
// 为了匹配路径,会将url中的/static去掉,剩下的部分,会在fileserver中查找。
mux.Handle("/static/", http.StripPrefix("/static", fileServer))
log.Println("Starting server on :4000")
err := http.ListenAndServe(":4000", mux)
log.Fatal(err)
}
该项目的目录结构如下
.
├── cmd
│ └── web
│ ├── handlers.go
│ └── main.go
├── go.mod
├── pkg
├── README.md
└── ui
├── html
│ ├── base.layout.html
│ ├── footer.partial.html
│ └── home.page.html
└── static
├── css
│ └── main.css
├── img
│ ├── favicon.ico
│ └── logo.png
└── js
在html页面模板中引用静态文件的代码为
<link rel='stylesheet' href='/static/css/main.css'>
<link rel='shortcut icon' href='/static/img/favicon.ico' type='image/x-icon'>
对应的页面效果为

使用起来很简单,但是还是有些地方需要注意的
- FileServer将所有请求路径都通过
path.Clean()
函数进行了标准化处理,然后才开始查找文件。这样做有助于避免目录遍历攻击。(目录遍历攻击,通常会通过..
和.
等查找上级目录并获取其他平级目录的文件,没有限制,整个磁盘的文件都会泄漏出去)。
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)
}
- 支持
range request
$ curl -i -H "Range: bytes=100-199" --output - http://localhost:8080/static/img/logo.png
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Length: 100
Content-Range: bytes 100-199/1075
Content-Type: image/png
Last-Modified: Mon, 07 Mar 2022 08:03:41 GMT
Date: Mon, 07 Mar 2022 08:55:44 GMT
h�j��ZbK�&�"b��dS�"V��M�PQ�S�T��x�PMC1���&�.(غ� ����&�"^"� ZI
- 支持
Last-Modified
和If-Modified-Since
。如果文件在用户上一次请求后没有被修改,那么就会返回304
,而不是文件内容。

Content-Type
会使用mime.TypeByExtension()
从文件扩展名自动识别。但可以通过mime.AddExtensionType()
函数进行扩展。-
http.ServeFile()
如果想要用这个函数来提供单独文件的下载,那么需要注意这个方法本身是没有使用path.Clean()
做url的标准化处理的。所以你使用filepath.Clean()
来自己处理这类安全问题。 - 禁止显示目录,有两种方法
- 方法1,在目录下放置空白的index.html文件,那么就会返回响应码200和空的内容。可以使用
find ./ui/static -type d -exec touch {}/index.html \;
命令。 - 方法2, 创建一个自定义的
http.FileSystem
,并在访问目录的时候,返回os.ErrNotExist
。 可参考 https://csdaomin.com/2022/03/07/golang-custom-http-filesystem/
- 方法1,在目录下放置空白的index.html文件,那么就会返回响应码200和空的内容。可以使用
Be First to Comment