I’m still fiddling with a web server idea, currently trying my umpteenth version of it in Go. One of the things I want to do is serve a bunch of different things from one binary; they would usually live behind Nginx anyway, and I like the simplicity of serving a bunch of (somewhat) dynamic, small sites from a single program.
So, how does one do it? Why, one does it with Goroutines!
I had expected that to be the answer, but even then I was surprised at the simplicity of this solution. You don’t even need channels, since http.ListenAndServe
is a blocking call if it’s not in a Goroutine.
Here’s the code, which should be self-explanatory.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// multiserve - serve multiple web sites from one Go binary. | |
// ---------- | |
// Just a demo for now. (C) Kevin Frost, github: biztos; | |
// MIT license if you like. | |
package main | |
import ( | |
"fmt" | |
"log" | |
"net/http" | |
) | |
type Server struct { | |
Name string | |
Mux *http.ServeMux | |
Port int | |
} | |
func (s *Server) Serve() { | |
fmt.Printf("%s server listening on port %d.\n", s.Name, s.Port) | |
portStr := fmt.Sprintf(":%d", s.Port) | |
http.ListenAndServe(portStr, s.Mux) | |
} | |
func NewServer(name string, port int) *Server { | |
homeHandler := func(w http.ResponseWriter, r *http.Request) { | |
log.Printf("%s shall serve!\n", name) | |
msg := fmt.Sprintf("Hello %s World!\n", name) | |
w.Write([]byte(msg)) | |
} | |
mux := http.NewServeMux() | |
mux.HandleFunc("/", homeHandler) | |
return &Server{ | |
Name: name, | |
Port: port, | |
Mux: mux, | |
} | |
} | |
func main() { | |
// Set up a router for each server. Here we just use two but | |
// you could probably have lots and lots. | |
servers := []*Server{ | |
NewServer("Foo", 8001), | |
NewServer("Bar", 8002), | |
} | |
// Start them using goroutines, but *not* for the last one: | |
final := len(servers) - 1 | |
for i, s := range servers { | |
if i == final { | |
s.Serve() | |
} else { | |
go s.Serve() | |
} | |
} | |
} |