【问题标题】:cannot get gorilla session value by key无法按键获取大猩猩会话值
【发布时间】:2015-03-30 01:00:18
【问题描述】:

我无法通过这种方式从会话中获取价值,它是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 是nil,虽然我设置它请求/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
}

【问题讨论】:

    标签: go gorilla


    【解决方案1】:

    您可能在初始化会话函数中使用 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 {    
            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
    }
    

    【讨论】:

      【解决方案2】:

      在您的 initSession() 函数中,您可以更改商店选项:

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

      Options 结构还包含一个重要的Path 字段,cookie 将应用于该字段。如果你不设置它,它的默认值为空字符串:""。这很可能会导致 cookie 不会与您的任何 url/路径匹配,因此将找不到您现有的会话。

      添加一个路径来匹配你的所有网址,如下所示:

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

      此外,您不应在每次调用 initSession() 时更改 store.Options,因为您在每个传入请求中都会调用它。只需在创建 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,
          }
      }
      

      【讨论】:

        【解决方案3】:

        由于我没有找到答案,我决定不使用 cookie 存储,而是使用 redis 存储进行会话。我找到了完整的工作示例here

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

        【讨论】:

          【解决方案4】:

          你的代码我玩了半天,终于发现它不起作用,因为你将加密密钥设置为非法值。

          /gorilla/sessions documentation 中写道:

          加密密钥(如果已设置)必须为 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>`
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-03-15
            • 1970-01-01
            • 1970-01-01
            • 2014-11-24
            • 2018-06-08
            • 2019-12-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多