如何使用 Go Web 服务器提供静态 html 文件?

如何使用 Go Web 服务器为 index.HTML (或其他静态 HTML 文件)提供服务?

我只是想要一个基本的,静态的 HTML 文件(如文章,例如) ,我可以从一个去网络服务器服务。HTML 应该可以在 go 程序之外进行修改,就像在使用 HTML 模板时一样。

这是我的网络服务器,只托管硬编码的文本(“ Hello world!”)。

package main


import (
"fmt"
"net/http"
)


func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello world!")
}


func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":3000", nil)
}
114425 次浏览

NOT a FTP server: That is something different than what I intended, which would be to serve the index.html homepage, like a normal web server would. Like, when I go to mydomain.com in my browser, I want index.html rendered.

That is mainly what "Writing Web Applications" describes, and what a project like hugo (static html site generator) does.

It is about reading a file, and responsing with a ContentType "text/html":

func (server *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := server.renderFile(w, r.URL.Path)
if err != nil {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusNotFound)
server.fn404(w, r)
}
}

with renderFile() essentially reading and setting the right type:

 file, err = ioutil.ReadFile(server.MediaPath + filename)
if ext != "" {
w.Header().Set("Content-Type", mime.TypeByExtension(ext))
}

That task is very easy with Golang net/http package.

All You need to do is:

package main


import (
"net/http"
)


func main() {
http.Handle("/", http.FileServer(http.Dir("./static")))
http.ListenAndServe(":3000", nil)
}

assuming that static files are in folder named static in the root directory of the project.

If it's in folder static, you'll have index.html file calling http://localhost:3000/ which will result in rendering that index file instead of listing all the files availible.

Additionally, calling any other file in that folder (for example http://localhost:3000/clients.html) will show that file, properly rendered by the browser (at least Chrome, Firefox and Safari :))

UPDATE: serving files from url different than "/"

If You want to serve files, say from folder ./public under url: localhost:3000/static You have to use additional function: func StripPrefix(prefix string, h Handler) Handler like this:

package main


import (
"net/http"
)


func main() {
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./public"))))
http.ListenAndServe(":3000", nil)
}

Thanks to that, all your files from ./public are avalible under localhost:3000/static

Without http.StripPrefix function, if you would try to access file localhost:3000/static/test.html, the server would look for it in ./public/static/test.html

This is because the server treats the whole URI as a relative path to the file.

Fortunately, it's easily solved with the built-in function.

I prefer using http.ServeFile for this over http.FileServer. I wanted directory browsing disabled, a proper 404 if files are missing and an easy way to special case the index file. This way, you can just drop the built binary into a folder and it will serve everything relative to that binary. Of course, you can use strings.Replace on p if you have the files stored in another directory.


func main() {
fmt.Println("Now Listening on 80")
http.HandleFunc("/", serveFiles)
log.Fatal(http.ListenAndServe(":80", nil))
}


func serveFiles(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.URL.Path)
p := "." + r.URL.Path
if p == "./" {
p = "./static/index.html"
}
http.ServeFile(w, r, p)
}

This is easy in golang as:

package main


import (
"log"
"net/http"
)


func main() {
log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("."))))
}

`

You can just do this and make sure to keep your HTML file as index.html

Example how custom serve mp3 file:

r := http.NewServeMux()
r.HandleFunc("/file/*", func(w http.ResponseWriter, r *http.Request) {


// Prepare file path
pathFile := strings.ReplaceAll(r.RequestURI, "/file/", "./my_path/")
f, err := os.Open(pathFile)
if f == nil || err != nil {
return
}


// Read file into memory
fileBytes, err := ioutil.ReadAll(f)
if err != nil {
log.Println(err)
_, _ = fmt.Fprintf(w, "Error file bytes")
return
}


// Check mime type
mime := http.DetectContentType(fileBytes)
if mime != "audio/mpeg" {
log.Println("Error file type")
_, _ = fmt.Fprintf(w, "Error file type")
return
}


// Custom headers
r.Header.Add("Content-Type", "audio/mpeg")
r.Header.Add("Cache-Control", "must-revalidate, post-check=0, pre-check=0")
r.Header.Add("Content-Description", "File Transfer")
r.Header.Add("Content-Disposition", "attachment; filename=file.mp3")
r.Header.Add("Content-Transfer-Encoding", "binary")
r.Header.Add("Expires", "0")
r.Header.Add("Pragma", "public")
r.Header.Add("Content-Length", strconv.Itoa(len(fileBytes)))
http.ServeFile(w, r, pathFile)
})
log.Fatal(http.ListenAndServe(":80", r))

If you only want to serve 1 file and not a full directory, you can use http.ServeFile

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})

This will serve the index.html file (if you have in the root) to the browser on localhost:8080

func main() {
port := flag.String("p", "8080", "port to serve on")
directory := flag.String("d", ".", "static file folder")
flag.Parse()


http.Handle("/", http.FileServer(http.Dir(*directory)))


log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}

You can also use the Gorilla Mux Router to server static files. Assuming you have a static folder and an index.html file in the root.

import  "github.com/gorilla/mux"


func main(){
router := mux.NewRouter()
fs := http.FileServer(http.Dir("./static/"))
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fs))
log.Fatal(http.ListenAndServe(":8080", router))
}