The code below produces the error further below. When I type "http://www.cnn.com/favicon.ico" straight into any browser it works without issue. I am guessing that I am missing some critical configuration for the reverse proxy. What is the minimum config needed for getting this to work?
package main
import (
"net/http"
"net/http/httputil"
"net/url"
"log"
)
func main(){
url, _ := url.Parse("http://www.cnn.com/favicon.ico")
proxy := httputil.NewSingleHostReverseProxy(url)
http.HandleFunc("/", proxy.ServeHTTP)
log.Fatal(http.ListenAndServe(":9090", nil))
}
Fastly error: unknown domain: localhost. Please check that this domain
has been added to a service.
Details: cache-lax8625-LAX
Happy 4th of July!
I made the following 2 changes to get it working:
Firstly, point the proxy at www.cnn.com instead of www.cnn.com/favicon.ico. Of course, now we must make our request to localhost:9090/favicon.ico.
Next, set the proxied request's Host field to the target host, not the host of the proxy which is localhost.
The code ends up looking like this:
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
)
type Director func(*http.Request)
func (f Director) Then(g Director) Director {
return func(req *http.Request) {
f(req)
g(req)
}
}
func hostDirector(host string) Director {
return func(req *http.Request) {
req.Host = host
}
}
func main() {
url, _ := url.Parse("http://www.cnn.com")
proxy := httputil.NewSingleHostReverseProxy(url)
d := proxy.Director
// sequence the default director with our host director
proxy.Director = Director(d).Then(hostDirector(url.Hostname()))
http.Handle("/", proxy)
log.Fatal(http.ListenAndServe(":9090", nil))
}
I am using GO's reverse proxy like this, but this does not work well
package main
import (
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
u, _ := url.Parse("http://www.darul.io")
http.ListenAndServe(":9000", httputil.NewSingleHostReverseProxy(u))
}
when I visit the http://localhost:9000, I am seeing not expected page
From this article A Proper API Proxy Written in Go:
httputil.NewSingleHostReverseProxy does not set the host of the request to the host of the destination server. If you’re proxying from foo.com to bar.com, requests will arrive at bar.com with the host of foo.com. Many webservers are configured to not serve pages if a request doesn’t appear from the same host.
You need to define a custom middleware to set the required host parameter:
package main
import (
"net/http"
"net/http/httputil"
"net/url"
)
func sameHost(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.Host = r.URL.Host
handler.ServeHTTP(w, r)
})
}
func main() {
// initialize our reverse proxy
u, _ := url.Parse("http://www.darul.io")
reverseProxy := httputil.NewSingleHostReverseProxy(u)
// wrap that proxy with our sameHost function
singleHosted := sameHost(reverseProxy)
http.ListenAndServe(":5000", singleHosted)
}
i am using Gorilla Mux for writing a REST API and i am having trouble organizing my routes, currently all of my routes are defined in the main.go file like this
//main.go
package main
import (
"NovAPI/routes"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Hello")
})
router.HandleFunc("/user", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "User")
})
router.HandleFunc("/route2", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route2")
})
router.HandleFunc("/route3", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route3")
})
// route declarations continue like this
http.ListenAndServe(":1128", router)
}
so what i want to do is take out and split this route declaration into multiple files, how would i go about doing that? thanks in advance.
You can modularize your routers independently into different packages, and mount them on the main router
Elaborating just a little on the following issue, you can come up with this approach, that makes it quite scalable (and easier to test, to some degree)
/api/router.go
package api
import (
"net/http"
"github.com/gorilla/mux"
)
func Router() *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/", home)
return router
}
func home(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("hello from API"))
}
/main.go
package main
import (
"log"
"net/http"
"strings"
"github.com/...yourPath.../api"
"github.com/...yourPath.../user"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/", home)
mount(router, "/api", api.Router())
mount(router, "/user", user.Router())
log.Fatal(http.ListenAndServe(":8080", router))
}
func mount(r *mux.Router, path string, handler http.Handler) {
r.PathPrefix(path).Handler(
http.StripPrefix(
strings.TrimSuffix(path, "/"),
handler,
),
)
}
func home(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Home"))
}
What about something like this ?
//main.go
package main
import (
"NovAPI/routes"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/hello", HelloHandler)
router.HandleFunc("/user", UserHandler)
router.HandleFunc("/route2", Route2Handler)
router.HandleFunc("/route3", Route3Handler)
// route declarations continue like this
http.ListenAndServe(":1128", router)
}
func HelloHandler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Hello")
}
func UserHandler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "User")
}
func Route2Handler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route2")
}
func Route3Handler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route3")
}
That way you can put your handlers in other files, or even other packages.
If you endup with additionnal dependencies like a database, you can even avoid the need of the global var using a constructor trick:
//main.go
func main() {
db := sql.Open(…)
//...
router.HandleFunc("/hello", NewHelloHandler(db))
//...
}
func NewHelloHandler(db *sql.DB) func(http.ResponseWriter, *http.Request) {
return func(res http.ResponseWriter, req *http.Request) {
// db is in the local scope, and you can even inject it to test your
// handler
fmt.Fprintln(res, "Hello")
}
}
I like checking out other projects in github to grab ideas on how to do stuff, and for these cases I usually take a look first at the Docker repo. This is the way they do it:
For the system's routes, define all handlers in system_routes.go and then initialize those routes on a NewRouter function in system.go.
type systemRouter struct {
backend Backend
routes []router.Route
}
func NewRouter(b Backend) router.Router {
r := &systemRouter{
backend: b,
}
r.routes = []router.Route{
local.NewOptionsRoute("/", optionsHandler),
local.NewGetRoute("/_ping", pingHandler),
local.NewGetRoute("/events", r.getEvents),
local.NewGetRoute("/info", r.getInfo),
local.NewGetRoute("/version", r.getVersion),
local.NewPostRoute("/auth", r.postAuth),
}
return r
}
// Routes return all the API routes dedicated to the docker system.
func (s *systemRouter) Routes() []router.Route {
return s.routes
}
Notice that systemRouter implements the router.Router interface and the Routes function returns a []router.Route, and their handlers are defined as
func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
instead of Go's standard http handler:
func(w http.ResponseWriter, r *http.Request)
So there's extra code of theirs to convert a Docker API Handler to a Go HTTP Handler at the makeHttpHandler function.
And finally, to add those routes to their mux router, on their server.go they implement several other functions to add middleware to their handlers.
If this is something that you think it's what you are looking for, then take your time to analyze the Docker code for their routes, and if you need me to elaborate more or if I missed anything, post a comment.
Since I am new to Go, I prefer a less verbose solution. In each module, we can create a Route function that expects a main route pointer and creates sub-routes to it. Our main.go file would be as follows
package main
import (
"net/http"
"github.com/user-name/repo-name/auth"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
auth.Router(r)
http.ListenAndServe(":8080", r)
}
then in auth module, we can create a route file
package auth
import "github.com/gorilla/mux"
func Router(r *mux.Router) {
routes := r.PathPrefix("/auth").Subrouter()
routes.HandleFunc("/register", Register)
}
I want create two http servers into one golang app. Example:
package main
import (
"io"
"net/http"
)
func helloOne(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world one!")
}
func helloTwo(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world two!")
}
func main() {
// how to create two http server instatce?
http.HandleFunc("/", helloOne)
http.HandleFunc("/", helloTwo)
go http.ListenAndServe(":8001", nil)
http.ListenAndServe(":8002", nil)
}
How to create two http server instance and add handlers for them?
You'll need to create separate http.ServeMux instances. Calling http.ListenAndServe(port, nil) uses the DefaultServeMux (i.e. shared). The docs for this are here: http://golang.org/pkg/net/http/#NewServeMux
Example:
func main() {
r1 := http.NewServeMux()
r1.HandleFunc("/", helloOne)
r2 := http.NewServeMux()
r2.HandleFunc("/", helloTwo)
go func() { log.Fatal(http.ListenAndServe(":8001", r1))}()
go func() { log.Fatal(http.ListenAndServe(":8002", r2))}()
select {}
}
Wrapping the servers with log.Fatal will cause the program to quit if one of the listeners doesn't function. If you wanted the program to stay up if one of the servers fails to start or crashes, you could err := http.ListenAndServe(port, mux) and handle the error another way.
Is this the right way to for a single Go web app (using Goji) to handle both http and https traffic?
package main
import (
"fmt"
"net/http"
"github.com/zenazn/goji/graceful"
"github.com/zenazn/goji/web"
)
func main() {
r := web.New()
//https://127.0.0.1:8000/r
r.Get("/r", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", "r")
})
go graceful.ListenAndServeTLS(":8000", "cert.pem", "key.pem", r)
r1 := web.New()
// http://127.0.0.1:8001/r1
r1.Get("/r1", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", "r1")
})
graceful.ListenAndServe(":8001", r1)
}
Or what is the best method for having both ports 8000 and 8001 listened to by a single Go web app?
You don't need to create a new object, you can simply pass r to graceful.ListenAndServe(":8001", r), unless of course you do a different action that depends on https.