Reputation: 1401
I am building a website that will use many routes and because of this I don't want individual handlers. My solution is to iterate over a list of endpoints. When I do this a cookie is set but not detected. The code below can be copy and pasted, just comments/uncomment the two route systems.
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
var tmpl *template.Template
const testCookieName = "testCookieName"
const testCookievalue = "testCookievalue"
func main(){
port :=":8088"
router := mux.NewRouter()
router.Use(middlewareSetCookie)
router.Use(middlewareCheckCookies)//no cookie sends page to /cookie for an error msg
router.Use(middlewareNoWWW)
router.Use(middlewareHeaders)
//Using individual routes works as expected and a cookie is set and detected.
/*
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, "index", "")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
router.HandleFunc("/cookie", func(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, "cookie", "")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
*/
//Given the number of routes I need I have to use a loop to iterate over all to keep the code base maintanable
//The cookie is set but not detected in the code below
/**/
pages := make(map[string]string)
pages["/"] = "index"
pages["/cookie"] = "cookie"
for k, v :=range pages{
router.HandleFunc(k, func(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, v, "")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}
var err error
tmpl, err = template.ParseGlob("views/*")
if err != nil {
panic(err.Error())
}
router.PathPrefix("/").HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir("./static/")).ServeHTTP(res, req)
})
fmt.Println("Server running on localhost" + port)
err = http.ListenAndServe(port, handlers.CompressHandler(router))
if err != nil {
log.Fatal(err)
}
}
func middlewareNoWWW(next http.Handler) http.Handler {
fmt.Println("middlewareNoWWW")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Host[0:4] == "www." {
target := "http://" + r.Host[4:]
http.Redirect(w, r, target, 301)
}
next.ServeHTTP(w, r)
})
}
func middlewareHeaders(next http.Handler) http.Handler {
fmt.Println("middlewareHeaders")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "max-age=2592000") // 30 days
w.Header().Set("Content-Encoding", "gzip")
w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
next.ServeHTTP(w, r)
})
}
func middlewareSetCookie(next http.Handler) http.Handler {
fmt.Println("middlewareSetCookie")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c, err := r.Cookie(testCookieName)
if err != nil || c.Value != testCookievalue {
cookie := http.Cookie{
Name: testCookieName,
Value: testCookievalue,
Path: "/",
HttpOnly: true,
MaxAge: 0,
Domain: "localhost"}
http.SetCookie(w, &cookie)
}
next.ServeHTTP(w, r)
})
}
func middlewareCheckCookies(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("middlewareCheckCookies")
fmt.Println(r.URL.String())
c, err := r.Cookie(testCookieName)
if err != nil || c.Value != testCookievalue {
redirectURL := "/cookie"
if r.URL.String() != redirectURL {
http.Redirect(w, r, redirectURL, http.StatusTemporaryRedirect)
return
}
}
next.ServeHTTP(w, r)
})
}
./views/cookie.html
{{define "cookie"}}no cookie set<a href="/">index</a>{{end}}
./views/index.html
{{define "index"}}<a href="/">index</a>{{end}}
Any clue to solving this?
Upvotes: 1
Views: 187
Reputation: 1668
The problem with your code is that it builds lousy closures for handler functions. It would help if you did not use uncontrollably changing (in this case by the loop) variables to build a closure. You can add the following line of code to fix the problem:
for k, v := range pages {
k, v := k, v // <-- this line
With that, each handler function will have its own set of external variables.
To be honest, I don't really understand what your initial problem is. What does it mean -- "a cookie is ... not detected"?
Upvotes: 2