Не может получить значение сеанса гориллы по ключу

Я не могу получить значение от сессии таким образом, это nil:

session := initSession(r)
valWithOutType := session.Values[key]

Полный код:

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "github.com/gorilla/sessions"
    "log"
    "net/http"
)

func main() {
    rtr := mux.NewRouter()
    rtr.HandleFunc("/setSession", handler1).Methods("GET")
    rtr.HandleFunc("/getSession", handler2).Methods("GET")
    http.Handle("/", rtr)
    log.Println("Listening...")
    http.ListenAndServe(":3000", http.DefaultServeMux)
}

func handler1(w http.ResponseWriter, r *http.Request) {
    SetSessionValue(w, r, "key", "value")
    w.Write([]byte("setSession"))
}

func handler2(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("getSession"))
    value := GetSessionValue(w, r, "key")
    fmt.Println("value from session")
    fmt.Println(value)
}

var authKey = []byte("secret") // Authorization Key

var encKey = []byte("encKey") // Encryption Key

var store = sessions.NewCookieStore(authKey, encKey)

func initSession(r *http.Request) *sessions.Session {
    store.Options = &sessions.Options{
        MaxAge:   3600 * 1, // 1 hour
        HttpOnly: true,
    }
    session, err := store.Get(r, "golang_cookie")
    if err != nil {
        panic(err)
    }

    return session
}

func SetSessionValue(w http.ResponseWriter, r *http.Request, key, value string) {
    session := initSession(r)
    session.Values[key] = value
    fmt.Printf("set session with key %s and value %s\n", key, value)
    session.Save(r, w)
}

func GetSessionValue(w http.ResponseWriter, r *http.Request, key string) string {
    session := initSession(r)
    valWithOutType := session.Values[key]
    fmt.Printf("valWithOutType: %s\n", valWithOutType)
    value, ok := valWithOutType.(string)
    if !ok {
        fmt.Println("cannot get session value by key: " + key)
    }
    return value
}

Выход:

myMac ~/forStack/session $ go run ./session.go
2015/01/30 16:47:26 Listening...

Сначала я открываю URL http://localhost:3000/setSession и получить вывод:

set session with key key and value value

Тогда я открываю URL http://localhost:3000/getSession и получить вывод:

valWithOutType: %!s(<nil>)
cannot get session value by key: key
value from session

Зачем valWithOutType ноль, хотя я установил его с просьбой /setSession?

Обновить

Я изменил код в соответствии с ответом @isza, но значение сеанса по-прежнему nil,

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "github.com/gorilla/sessions"
    "log"
    "net/http"
)

func main() {
    rtr := mux.NewRouter()
    rtr.HandleFunc("/setSession", handler1).Methods("GET")
    rtr.HandleFunc("/getSession", handler2).Methods("GET")
    http.Handle("/", rtr)
    log.Println("Listening...")
    store.Options = &sessions.Options{
        MaxAge:   3600 * 1, // 1 hour
        HttpOnly: true,
        Path:     "/", // to match all requests
    }
    http.ListenAndServe(":3000", http.DefaultServeMux)

}

func handler1(w http.ResponseWriter, r *http.Request) {
    SetSessionValue(w, r, "key", "value")
    w.Write([]byte("setSession"))
}

func handler2(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("getSession"))
    value := GetSessionValue(w, r, "key")
    fmt.Println("value from session")
    fmt.Println(value)
}

var authKey = []byte("secret") // Authorization Key

var encKey = []byte("encKey") // Encryption Key

var store = sessions.NewCookieStore(authKey, encKey)

func initSession(r *http.Request) *sessions.Session {
    session, err := store.Get(r, "golang_cookie")
    if err != nil {
        panic(err)
    }
    return session
}

func SetSessionValue(w http.ResponseWriter, r *http.Request, key, value string) {
    session := initSession(r)
    session.Values[key] = value
    fmt.Printf("set session with key %s and value %s\n", key, value)
    session.Save(r, w)
}

func GetSessionValue(w http.ResponseWriter, r *http.Request, key string) string {
    session := initSession(r)
    valWithOutType := session.Values[key]
    fmt.Printf("valWithOutType: %s\n", valWithOutType)
    value, ok := valWithOutType.(string)
    if !ok {
        fmt.Println("cannot get session value by key: " + key)
    }
    return value
}

4 ответа

Что вы, вероятно, делаете в своей функции сеанса инициализации с помощью метода get, вы перезапускаете весь сеанс снова, поэтому каждый раз, когда вы делаете это, сеанс пуст. Я быстро взломал то, что ты написал, чтобы показать, где твоя ошибка. Пожалуйста, обойдите этот пример!

package appSession

import (        
    "net/http"
    "fmt"
    "log"
    "github.com/gorilla/sessions"    
)

var appSession *sessions.Session;

var authKey = []byte("qwer")
var encKey = []byte("asdf")

var store = sessions.NewCookieStore(authKey, encKey)    

func initSession(r *http.Request) *sessions.Session {

    log.Println("session before get", appSession)

    if appSession == nil {        
    }else{    
        return appSession;    
    }

    session, err := store.Get(r, "golang_cookie")
    appSession = session;

    log.Println("session after get", session)
    if err != nil {
        panic(err)
    }
    return session
}

func SetSessionValue(w http.ResponseWriter, r *http.Request, key, value string) {
    session := initSession(r)
    session.Values[key] = value
    fmt.Printf("set session with key %s and value %s\n", key, value)
    session.Save(r, w)
}

func GetSessionValue(w http.ResponseWriter, r *http.Request, key string) string {   
    session := initSession(r)
    valWithOutType := session.Values[key]
    fmt.Printf("valWithOutType: %s\n", valWithOutType)
    value, ok := valWithOutType.(string)
    log.Println("returned value: ", value);

    if !ok {
        fmt.Println("cannot get session value by key: " + key)
    }
    return value
}

В вашем initSession() Функция изменения параметров магазина:

store.Options = &sessions.Options{
    MaxAge:   3600 * 1, // 1 hour
    HttpOnly: true,
}

Options структура также содержит важный Path поле, к которому будет применяться cookie. Если вы не установите его, его значением по умолчанию будет пустая строка: "", Скорее всего, это приведет к тому, что файл cookie не будет сопоставлен ни с одним из ваших URL / путей, поэтому существующий сеанс не будет найден.

Добавьте путь, чтобы соответствовать всем вашим URL, как это:

store.Options = &sessions.Options{
    Path:     "/",      // to match all requests
    MaxAge:   3600 * 1, // 1 hour
    HttpOnly: true,
}

Также не стоит менять store.Options в каждом вызове initSession() так как вы звоните это в каждом входящем запросе. Просто установите это один раз, когда вы создаете store как это:

var store = sessions.NewCookieStore(authKey, encKey)

func init() {
    store.Options = &sessions.Options{
        Path:     "/",      // to match all requests
        MaxAge:   3600 * 1, // 1 hour
        HttpOnly: true,
    }
}

Поскольку я не нашел ответа, я решил не использовать cookie store, а использовать redis store для сессий. И я нашел полный рабочий пример здесь

package main

import (
    "fmt"
    "github.com/aaudis/GoRedisSession"
    "log"
    "net/http"
)

var (
    redis_session *rsess.SessionConnect
)

func main() {
    // Configurable parameters
    rsess.Prefix = "sess:" // session prefix (in Redis)
    rsess.Expire = 1800    // 30 minute session expiration

    // Connecting to Redis and creating storage instance
    temp_sess, err := rsess.New("sid", 0, "127.0.0.1", 6379)
    if err != nil {
        log.Printf("%s", err)
    }

    redis_session = temp_sess // assing to global variable

    http.HandleFunc("/", Root)
    http.HandleFunc("/get", Get)
    http.HandleFunc("/set", Set)
    http.HandleFunc("/des", Des)
    http.ListenAndServe(":8888", nil)
}

func Root(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("Content-Type", "text/html")
    fmt.Fprintf(w, `
        Redis session storage example:<br><br>
        <a href="/set">Store key in session</a><br>
        <a href="/get">Get key value from session</a><br>
        <a href="/des">Destroy session</a>
    `)
}

// Destroy session
func Des(w http.ResponseWriter, r *http.Request) {
    s := redis_session.Session(w, r)
    s.Destroy(w)
    fmt.Fprintf(w, "Session deleted!")
}

// Set variable to session
func Set(w http.ResponseWriter, r *http.Request) {
    s := redis_session.Session(w, r)
    s.Set("UserID", "1000")
    fmt.Fprintf(w, "Setting session variable done!")
}

// Get variable from session
func Get(w http.ResponseWriter, r *http.Request) {
    s := redis_session.Session(w, r)
    fmt.Fprintf(w, "Value %s", s.Get("UserID"))
}

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

В документации /gorilla/session написано:

Ключ шифрования, если он установлен, должен иметь размер 16, 24 или 32 байта для выбора режимов AES-128, AES-192 или AES-256.

Так как я считаю, что var encKey = []byte("encKey") просто не следует этому требованию. В свою очередь, cookie не устанавливается в первую очередь.

Смотрите мой код для справки. Я в основном добавил еще вывод командной строки и использовал шаблон с перенаправлением:

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "github.com/gorilla/sessions"
    "html/template"
    "log"
    "net/http"
)

var authKey = []byte("secret") // Authorization Key

//var encKey = []byte("encKey") // Encryption Key

var store sessions.Store

func main() {
    rtr := mux.NewRouter()
    rtr.HandleFunc("/setSession/", handler1).Methods("GET")
    rtr.HandleFunc("/getSession/", handler2).Methods("GET")
    http.Handle("/", rtr)
    store = GetCookieStore()
    log.Println("Listening...")
    http.ListenAndServe(":4000", http.DefaultServeMux)

}

//setting up the cookiestore
func GetCookieStore() sessions.Store {

    //maxAge := 3600 * 1 // 1 hour
    maxAge := 100
    //cookieStore := sessions.NewCookieStore(authKey, encKey)
    cookieStore := sessions.NewCookieStore(authKey)

    cookieStore.Options.HttpOnly = true
    cookieStore.Options.Path = "/" // to match all requests
    cookieStore.MaxAge(maxAge)

    return cookieStore
}

func handler1(w http.ResponseWriter, r *http.Request) {
    t, _ := template.New("foo").Parse(getSessionTemplate)

    SetSessionValue(w, r, "key", "value")
    session := initSession(r)
    fmt.Print("handler1: ")
    fmt.Println(session)

    Value, ok := session.Values["key"].(string)
    if !ok {
        fmt.Println("Type assertion to string failed or session value could not be retrieved.")
    }

    t.Execute(w, Value)

}

func handler2(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("getSession"))
    session := initSession(r)
    fmt.Print("handler2: ")
    fmt.Println(session)
    value := GetSessionValue(w, r, "key")
    fmt.Println("value from session")
    fmt.Println(value)
}

func initSession(r *http.Request) *sessions.Session {
    session, err := store.Get(r, "_golang_cookie")
    if err != nil {
        panic(err)
    }
    return session
}

func SetSessionValue(w http.ResponseWriter, r *http.Request, key, value string) {
    session := initSession(r)
    session.Values[key] = value
    fmt.Printf("set session with key %s and value %s\n", key, value)
    session.Save(r, w)
    fmt.Print("setsession: ")
    fmt.Println(session)
}

func GetSessionValue(w http.ResponseWriter, r *http.Request, key string) string {
    session := initSession(r)
    fmt.Print("getsession: ")
    fmt.Println(session)
    valWithOutType := session.Values[key]
    fmt.Printf("valWithOutType: %s\n", valWithOutType)
    value, ok := valWithOutType.(string)
    if !ok {
        fmt.Println("cannot get session value by key: " + key)
    }

    return value
}

var getSessionTemplate = `
<p><label>Session value set:</label></p>
<p><label>Value: is now: {{.}}</label></p>

<p><a href="/getSession/">Getsession</a></p>`
Другие вопросы по тегам