Сеанс промежуточного программного обеспечения для Go? - PullRequest
0 голосов
/ 03 мая 2019
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
    }
}

Все мои обработчики используют сеансы Gorilla . Как я могу избежать store.Get указания сеанса в каждом из моих обработчиков, т.е. повторение кода?

Другая проблема, есть ли лучший способ присвоить шаблону значения сеанса, отличные от явного, например:

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

Образцы кода взяты из https://github.com/kaihendry/internal-google-login

1 Ответ

2 голосов
/ 03 мая 2019

Для промежуточного программного обеспечения вы можете определить функцию, которая принимает обработчик в качестве аргумента и возвращает другой обработчик в качестве результата.

func sessionMiddleware(h http.HandlerFunc) http.HandlerFunc {
    // ...
}

Возвращенный обработчик может store.Get сеанс, если его нет, returnошибка, если она присутствует, сохранить сеанс в контексте запроса и затем вызвать фактический обработчик.

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)
    }
}

Теперь вашим обработчикам все равно нужно будет «получить» значение сеанса из контекста, однако любой обработчик, которыйупакован в 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
    }
}

И для регистрации обработчика вы должны сделать:

app.HandleFunc("/", sessionMiddleware(indexHandler))

Если это все еще слишком много повторений кода на ваш вкус, вы можете передать сеанс непосредственно вашим обработчикам, однако вам придется изменить их подпись.

type SessionHandler func(w http.ResponseWriter, r *http.Request, s *session.Session)

Затем обновите свойобработчики.

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
    }
}

И вы можете определить часть промежуточного программного обеспечения для типа 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)
}

AnЗатем зарегистрируйте обработчик:

app.Handle("/", SessionHandler(indexHandler))
...