Go 的会话中间件?

hen*_*dry 1 session go gorilla

func indexHandler(w http.ResponseWriter, req *http.Request) {
    session, err := store.Get(req, sessionName)
    if err != nil {
        log.WithError(err).Error("bad session")
        http.SetCookie(w, &http.Cookie{Name: sessionName, MaxAge: -1, Path: "/"})
    }
    err = views.ExecuteTemplate(w, "index.html", session.Values)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}
Run Code Online (Sandbox Code Playgroud)

我所有的处理程序都使用Gorilla 会话。如何避免store.Get在我的每个处理程序中调用会话,即代码重复?

另一个问题是,是否有更好的方法来为模板提供会话值,而不是一种明确的方式,例如:

err = views.ExecuteTemplate(w, "index.html",
    struct {
        Session map[interface{}]interface{},
        ...other handler specific data for the template
    }{
        session.Values,
        ...
    })
Run Code Online (Sandbox Code Playgroud)

代码示例源自https://github.com/kaihendry/internal-google-login

mko*_*iva 5

对于中间件,您可以定义一个函数,该函数将处理程序作为参数并返回另一个处理程序作为其结果。

func sessionMiddleware(h http.HandlerFunc) http.HandlerFunc {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

返回的处理程序可以store.Get会话,如果它不存在,则返回错误,如果存在,则将会话存储到请求的上下文中,然后调用实际的处理程序。

func sessionMiddleware(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        session, err := store.Get(r, sessionName)
        if err != nil {
            log.WithError(err).Error("bad session")
            http.SetCookie(w, &http.Cookie{Name: sessionName, MaxAge: -1, Path: "/"})
            return
        }

        r = r.WithContext(context.WithValue(r.Context(), "session", session))
        h(w, r)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您的处理程序仍然需要从上下文“获取”会话值,但是 sessionMiddleware 包装的任何处理程序都可以假定,在执行时,会话存在于上下文中,因此它可以跳过错误检查。

func indexHandler(w http.ResponseWriter, req *http.Request) {
    session := req.Context().Value("session").(*sessions.Session)
    err := views.ExecuteTemplate(w, "index.html", session.Values)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}
Run Code Online (Sandbox Code Playgroud)

要注册处理程序,您将执行以下操作:

app.HandleFunc("/", sessionMiddleware(indexHandler))
Run Code Online (Sandbox Code Playgroud)

如果这仍然是您喜欢的太多代码重复,您可以将会话直接传递给您的处理程序,但是您必须更改他们的签名。

type SessionHandler func(w http.ResponseWriter, r *http.Request, s *session.Session)
Run Code Online (Sandbox Code Playgroud)

然后更新您的处理程序。

func indexHandler(w http.ResponseWriter, req *http.Request, s *session.Session) {
    err := views.ExecuteTemplate(w, "index.html", s.Values)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将SessionHandler类型上的中间件部分定义为方法。

func (h SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        session, err := store.Get(r, sessionName)
        if err != nil {
            log.WithError(err).Error("bad session")
            http.SetCookie(w, &http.Cookie{Name: sessionName, MaxAge: -1, Path: "/"})
            return
        }

        h(w, r, session)
}
Run Code Online (Sandbox Code Playgroud)

然后要注册处理程序,您将执行以下操作:

app.Handle("/", SessionHandler(indexHandler))
Run Code Online (Sandbox Code Playgroud)