If you ever have the need to combine a plain HTTP webserver with a gRPC server on the same port, then you can use cmux to do so.
You can do something like:
package main import ( "log" "net" "net/http" "github.com/soheilhy/cmux" "golang.org/x/sync/errgroup" "google.golang.org/grpc" ) func main() { // Create the listener l, err := net.Listen("tcp", ":8080") if err != nil { log.Fatal(err) } // Create a new cmux instance m := cmux.New(l) // Create a grpc listener first grpcListener := m.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) // All the rest is assumed to be HTTP httpListener := m.Match(cmux.Any()) // Create the servers grpcServer := grpc.NewServer() httpServer := &http.Server{} // Use an error group to start all of them g := errgroup.Group{} g.Go(func() error { return grpcServer.Serve(grpcListener) }) g.Go(func() error { return httpServer.Serve(httpListener) }) g.Go(func() error { return m.Serve() }) // Wait for them and check for errors err = g.Wait() if err != nil { log.Fatal(err) } }
This also demonstrates how the errgroup module can be used. The Wait
method blocks until all function calls from the Go
method have returned, then returns the first non-nil error (if any) from them.
PS: the example itself doesn't actually do something useful as we didn't register any gRPC functions neither did I define HTTP handlers.