Google app engine 如何在Google App Engine标准环境下避免Gorilla会话的内存泄漏?

Google app engine 如何在Google App Engine标准环境下避免Gorilla会话的内存泄漏?,google-app-engine,go,memory-leaks,gorilla,Google App Engine,Go,Memory Leaks,Gorilla,我正在使用Gorilla在Google App Engine上启用会话变量。到目前为止,我只导入了“github.com/gorilla/sessions”,但gorilla的页面显示: 如果您没有使用gorilla/mux,则需要使用 context.ClearHandler为,否则将泄漏内存!一种简单的方法 这样做是为了在调用http.listenandservice时包装顶级mux: http.listendServe(“:8080”, ClearHandler(http.DefaultS

我正在使用Gorilla在Google App Engine上启用会话变量。到目前为止,我只导入了“github.com/gorilla/sessions”,但gorilla的页面显示:

如果您没有使用gorilla/mux,则需要使用 context.ClearHandler为,否则将泄漏内存!一种简单的方法 这样做是为了在调用http.listenandservice时包装顶级mux:

http.listendServe(“:8080”, ClearHandler(http.DefaultServeMux))

我的问题是如何将其应用于App Engine标准环境,据我所知,该环境默认不使用http.ListenAndServe。我的代码如下所示:

package test

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

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {

    var cookiestore =  sessions.NewCookieStore([]byte("somesecret"))
    session, _ := cookiestore.Get(r, "session")
    session.Values["foo"] = "bar"

    fmt.Fprintf(w, "session value is %v", session.Values["foo"])

}
func handler(w http.ResponseWriter, r *http.Request) {
    defer context.Clear(r)

    var cookiestore =  sessions.NewCookieStore([]byte("somesecret"))
    session, _ := cookiestore.Get(r, "session")
    session.Values["foo"] = "bar"

    fmt.Fprintf(w, "session value is %v", session.Values["foo"])
}

这样会导致内存泄漏吗?

Gorilla还提供了一个
context.Clear()
选项,您可以根据以下文档将该选项放入请求处理程序:

因此,处理程序func将变成:

func handler(w http.ResponseWriter, r *http.Request) {

    var cookiestore =  sessions.NewCookieStore([]byte("somesecret"))
    session, _ := cookiestore.Get(r, "session")
    session.Values["foo"] = "bar"

    fmt.Fprintf(w, "session value is %v", session.Values["foo"])
    context.Clear(r)
}

您引用的文档告诉您需要做的一切:使用包装处理程序。由于“仅”具有处理程序函数而不是,因此可以使用适配器获取实现http.handler的值:

func init() {
    http.Handle("/", context.ClearHandler(http.HandlerFunc(handler)))
}
您需要为您注册的每个处理程序执行此操作。这就是为什么文档提到只包装传递给的根处理程序更容易(这样就不必包装其他非顶级处理程序)。但这不是唯一的方法,只是最简单/最短的方法

如果您自己不调用http.listendServe()(如在App Engine中),或者您没有一个根处理程序,那么您需要手动包装您注册的所有处理程序

请注意,
context.ClearHandler()
返回的处理程序没有做任何神奇的事情,它所做的只是在调用您传递的处理程序之后进行调用。因此,您可以同样轻松地在处理程序中调用
context.Clear()
,以实现相同的效果

如果这样做,一件重要的事情是使用
defer
,就好像出于某种原因无法访问
context.Clear()
(例如,遇到前面的
return
语句),您将再次泄漏内存。即使您的函数崩溃,也会调用延迟函数。所以应该这样做:

package test

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

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {

    var cookiestore =  sessions.NewCookieStore([]byte("somesecret"))
    session, _ := cookiestore.Get(r, "session")
    session.Values["foo"] = "bar"

    fmt.Fprintf(w, "session value is %v", session.Values["foo"])

}
func handler(w http.ResponseWriter, r *http.Request) {
    defer context.Clear(r)

    var cookiestore =  sessions.NewCookieStore([]byte("somesecret"))
    session, _ := cookiestore.Get(r, "session")
    session.Values["foo"] = "bar"

    fmt.Fprintf(w, "session value is %v", session.Values["foo"])
}
还请注意,会话存储创建只应执行一次,因此将其从处理程序移出到全局变量。并检查和处理错误,以节省您的一些头痛。最后建议的代码是:

package test

import (
    "fmt"
    "net/http"
    "log"

    "github.com/gorilla/context"
    "github.com/gorilla/sessions"
)

func init() {
    http.Handle("/", context.ClearHandler(http.HandlerFunc(handler)))
}

var cookiestore =  sessions.NewCookieStore([]byte("somesecret"))

func handler(w http.ResponseWriter, r *http.Request) {
    session, err := cookiestore.Get(r, "session")
    if err != nil {
        // Handle error:
        log.Printf("Error getting session: %v", err)
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    session.Values["foo"] = "bar"

    fmt.Fprintf(w, "session value is %v", session.Values["foo"])
}

抱歉,我在上面的代码中遇到以下错误:无法将handler(type func(http.ResponseWriter,*http.Request))用作“github.com/gorilla/context”参数中的类型http.handler。ClearHandler:func(http.ResponseWriter,*http.Request)未实现http.handler(缺少ServeHTTP方法),谢谢,在我删除旧的会话cookie后,它工作了(之前它说“securecookie:the value is not valid”,可能是因为使用了不同的Previor键)