Basic Http & File Server in Go
Golang has a built-in net/http
package that allows us to build a http server like Nginx or Apache. I'm going through serveral levels on how to build it.
The Basics
package main
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Hello World"))
})
http.ListenAndServe(":8000", nil)
}
After we run go main.go
the server runs on port 8000
displaying Hello World
. This program is composed of several parts:
An
http.HandleFunc()
handles http requests and returns responses accordingly.The
http.ListenAndServe()
listens to port8000
to receives requests.
However, we only respond Hello World
to all responses. How about we serve some HTML pages accordingly?
Serving static files
The way we serve static files are to render files according to reqesuted path.
package main
import (
"bufio"
"net/http"
"os"
"strings"
)
type MyHandler struct {
http.Handler
}
func ContentType(path string) (contentType string) {
if strings.HasSuffix(path, ".css") {
contentType = "text/css"
} else if strings.HasSuffix(path, ".html") {
contentType = "text/html"
} else if strings.HasSuffix(path, ".js") {
contentType = "application/javascript"
} else if strings.HasSuffix(path, ".png") {
contentType = "image/png"
} else {
contentType = "text/plain"
}
return
}
// We create a custom handler
func (this *MyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
path := "./public" + req.URL.Path
// Open a file, which does not render it but keep it ready for read
f, err := os.Open(path)
// if a file exists, check its content type, or return 404
if err == nil {
// read the content to buffer in order to save memory
bufferedReader := bufio.NewReader(f)
// check content type of the file according to its suffix
w.Header().Add("Content Type", ContentType(path))
// write the file content to the response
bufferedReader.WriteTo(w)
} else {
w.WriteHeader(404)
w.Write([]byte("404 - " + http.StatusText(404)))
}
}
func main() {
// use the custom handler
http.Handle("/", new(MyHandler))
http.ListenAndServe(":8000", nil)
}
Serving static files, an easier way
The code above is actually built-in in Go library, so we can put it like:
package main
import "net/http"
func main() {
http.ListenAndServe(":8000", http.FileServer(http.Dir("public")))
}
And we're done.