1

I'm trying to implement two routes using the Chi router. One should be invoked only if the "host" header is set to example.com. But only the lastly added route is invoked.

r := chi.NewRouter()
r.Use(middleware.Logger)

middlewareHeader := middleware.RouteHeaders().Route("Host", "example.com", middleware.New(r)).Handler
r.With(middlewareHeader).MethodFunc("get", "/", func(w http.ResponseWriter, r *http.Request) {
    log.Println("Host: example.com")
    echo(w, r)
})

middlewareNone := middleware.RouteHeaders().Handler
r.With(middlewareNone).MethodFunc("get", "/", func(w http.ResponseWriter, r *http.Request) {
    echo(w, r)
})

srv := &http.Server{
    Handler:      r,
    Addr:         "127.0.0.1:8080",
    WriteTimeout: 15 * time.Second,
    ReadTimeout:  15 * time.Second,
}

log.Fatal(srv.ListenAndServe())
user672009
  • 4,379
  • 8
  • 44
  • 77
  • You cannot assign multiple funcs to path. Your handleFunc have to split the logic. You could create 2 additional paths and redirect to them based on header. – medasx Jul 13 '22 at 08:57
  • @medasx Could you perhaps elaborate a bit more on how to do that? It sounds like that could be a solution – user672009 Jul 13 '22 at 13:35

1 Answers1

1

As mentioned on comment: you cannot assign multiple handlers to one route.

RouteHeaders is a neat little header-based router that allows you to direct the flow of a request through a middleware stack based on a request header.

RouteHeaders is used to put your request through specific middleware stack, not to change routes. You can still use it but middleware has to redirect to other route.

Options:


1. Create second route and redirect in middleware.

func redirectOnHeader(header, value string) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if r.Header.Get(header) == value {
                http.Redirect(w, r, "/with-header", http.StatusMovedPermanently)
                return
            }
            next.ServeHTTP(w, r)
        })
    }
}

then call the middleware on desired route

r := chi.NewRouter()

r.With(redirectOnHeader("Host", "example.com")).Get("/", func(w http.ResponseWriter, r *http.Request) {
        echo(w, r)
})
r.Get("/with-headers", func(w http.ResponseWriter, r *http.Request) {
        echo(w, r)
})

2. Use second router and RouteHeaders

As in example in docs.

Note that you need 2 routers on order to have 2 "/" routes.

r := chi.NewRouter()
anotherR := chi.NewRouter()

r.Use(middleware.RouteHeaders().
    Route("Host", "example.com", middleware.New(r)).
    RouteDefault(middleware.New(anotherR)).
    Handler)

r.Get("/", func(w http.ResponseWriter, r *http.Request) {
    echo(w, r)
})
anotherR.Get("/", func(w http.ResponseWriter, r *http.Request) {
    echo(w, r)
})

3. Implement two logic in one HandlerFunc

func(w http.ResponseWriter, r *http.Request) {
    if r.Header.Get(header) == value {
        // do something
        return
    }
    // do something else
})
medasx
  • 634
  • 4
  • 7