目录
概述
http.FileServer
原始方式
原始方式比较简单粗暴,直接读取文件,然后返回给客户端。
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/static/",fileHandler)
server := &http.Server {
Addr: ":8080",Handler: mux,}
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
/static//static//public/
/static///static/hello.html/static//static
接下来,我们看看文件处理器的实现:
func fileHandler(w http.ResponseWriter,r *http.Request) {
path := "." + r.URL.Path
fmt.Println(path)
f,err := os.Open(path)
if err != nil {
Error(w,toHTTPError(err))
return
}
defer f.Close()
d,err := f.Stat()
if err != nil {
Error(w,toHTTPError(err))
return
}
if d.IsDir() {
DirList(w,r,f)
return
}
data,err := IoUtil.ReadAll(f)
if err != nil {
Error(w,toHTTPError(err))
return
}
ext := filepath.Ext(path)
if contentType := extensionToContentType[ext]; contentType != "" {
w.Header().Set("Content-Type",contentType)
}
w.Header().Set("Content-Length",strconv.FormatInt(d.Size(),10))
w.Write(data)
}
staticContent-TypeContent-Type
var extensionToContentType = map[string]string {
".html": "text/html; charset=utf-8",".css": "text/css; charset=utf-8",".js": "application/javascript",".xml": "text/xml; charset=utf-8",".jpg": "image/jpeg",}
如果该路径表示的是一个目录,那么返回目录下所有文件与目录的列表:
func DirList(w http.ResponseWriter,r *http.Request,f http.File) {
dirs,err := f.Readdir(-1)
if err != nil {
Error(w,http.StatusInternalServerError)
return
}
sort.Slice(dirs,func(i,j int) bool { return dirs[i].Name() < dirs[j].Name() })
w.Header().Set("Content-Type","text/html; charset=utf-8")
fmt.Fprintf(w,"<pre>\n")
for _,d := range dirs {
name := d.Name()
if d.IsDir() {
name += "/"
}
url := url.URL{Path: name}
fmt.Fprintf(w,"<a href=\"%s\">%s</a>\n",url.String(),name)
}
fmt.Fprintf(w,"</pre>\n")
}
上面的函数先读取目录下第一层的文件和目录,然后按照名字排序。最后拼装成包含超链接的 HTML 返回。用户可以点击超链接访问对应的文件或目录。
toHTTPErrorError
func toHTTPError(err error) int {
if os.IsNotExist(err) {
return http.StatusNotFound
}
if os.IsPermission(err) {
return http.StatusForbidden
}
return http.StatusInternalServerError
}
func Error(w http.ResponseWriter,code int) {
w.WriteHeader(code)
}
static
static
├── folder
│ ├── file1.txt
│ └── file2.txt
│ └── file3.txt
├── hello.css
├── hello.html
├── hello.js
└── hello.txt
运行程序看看效果:
$ go run main.go
localhost:8080/static/hello.html
hello.html
<!-- hello.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<Meta charset="UTF-8">
<Meta name="viewport" content="width=device-width,initial-scale=1.0">
<Meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Go Web 编程之 静态文件</title>
<link rel="stylesheet" href="/static/hello.css">
</head>
<body>
<p class="greeting">Hello World!</p>
<script src="/static/hello.js"></script>
</body>
</html>
/static/
.greeting {
font-family: sans-serif;
font-size: 15px;
font-style: italic;
font-weight: bold;
}
console.log("Hello World!")
“Hello World!“字体显示为 css 设置的样式,通过观察控制台也能看到 js 打印的信息。
localhost:8080/static/
可以依次点击列表中的文件查看其内容。
hello.css
hello.js
folderfile1.txt
静态文件的请求路径也会输出到运行服务器的控制台中:
$ go run main.go
./static/
./static/hello.css
./static/hello.js
./static/folder/
./static/folder/file1.txt
http.FileServer
http.FileServer
先来看看如何使用:
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.Handle("/static/",http.FileServer(http.Dir("")))
server := &http.Server {
Addr: ":8080",}
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
http.Server
http.FileServerhttp.FileSystem
// src/net/http/fs.go
type FileSystem interface {
Open(name string) (File,error)
}
http.Dirhttp.Dirstringhttp.Dir("")
// src/net/http/fs.go
type Dir string
http.DirOpen
http.FileServerhttp.HandlerHandlehttp.FileServerhttp.DirOpen/static/hello.htmlhttp.Dir../static/hello.html
http.Dirpublichttp.StripPrefix
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.Handle("/static/",http.StripPrefix("/static",http.FileServer(http.Dir("./public"))))
server := &http.Server {
Addr: ":8080",}
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
localhost:8080/static/hello.html./public/hello.html/static/index.htmlhttp.StripPrefix/static/index.htmlhttp.Dir./public./public/hello.html
http.FileServer
// src/mime/type.go
var builtinTypesLower = map[string]string{
".css": "text/css; charset=utf-8",".gif": "image/gif",".htm": "text/html; charset=utf-8",".html": "text/html; charset=utf-8",".jpeg": "image/jpeg",".js": "application/javascript",".mjs": "application/javascript",".pdf": "application/pdf",".png": "image/png",".svg": "image/svg+xml",".wasm": "application/wasm",".webp": "image/webp",".xml": "text/xml; charset=utf-8",}
http.FileServersrc/net/http/sniff.go
http.ServeContent
http.FileServernet/httpServeContent
file
package main
import (
"fmt"
"log"
"net/http"
"os"
"time"
)
func ServeFileContent(w http.ResponseWriter,name string,modTime time.Time) {
f,err := os.Open(name)
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w,"open file error:",err)
return
}
defer f.Close()
fi,err := f.Stat()
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w,"call stat error:",err)
return
}
if fi.IsDir() {
w.WriteHeader(400)
fmt.Fprint(w,"no such file:",name)
return
}
http.ServeContent(w,name,fi.ModTime(),f)
}
func fileHandler(w http.ResponseWriter,r *http.Request) {
query := r.URL.Query()
filename := query.Get("file")
if filename == "" {
w.WriteHeader(400)
fmt.Fprint(w,"filename is empty")
return
}
ServeFileContent(w,filename,time.Time{})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/show",}
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
http.ServeContenthttp.ResponseWriterhttp.RequestnamemodTimeio.ReadSeeker
modTimeLast-ModifiedIf-Modified-SinceServeContentmodTimeServeContentio.ReadSeeker*os.Fileio.ReadSeeker
使用场景
http.FileServerhttp.FileServer
package main
import (
"flag"
"log"
"net/http"
)
var (
ServeDir string
)
func init() {
flag.StringVar(&ServeDir,"sd","./","the directory to serve")
}
func main() {
flag.Parse()
mux := http.NewServeMux()
mux.Handle("/static/",http.StripPrefix("/static/",http.FileServer(http.Dir(ServeDir))))
server := &http.Server {
Addr: ":8080",}
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
在上面的代码中,我们构建了一个简单的文件服务器。编译之后,将想浏览的目录作为参数传给命令行选项,就可以浏览和下载该目录下的文件了:
$ ./main.exe -sd D:/code/golang
可以将端口也作为命令行选项,这样做出一个通用的文件服务器,编译之后就可以在其它机器上使用了
小编说
以上是编程之家为你收集整理的golang web 静态文件全部内容。
如果觉得编程之家网站内容还不错,欢迎将编程之家推荐给好友。