正确使用go context.Context

Bru*_*ira 5 concurrency go gorilla

我刚刚阅读了文章:在 Go 中构建您自己的 Web 框架,为了在处理程序之间共享值,我选择了 context.Context 并按以下方式使用它在处理程序和中间件之间共享值:

type appContext struct {
    db     *sql.DB
    ctx    context.Context
    cancel context.CancelFunc
 }


func (c *appContext)authHandler(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request {
        defer c.cancel() //this feels weird
        authToken := r.Header.Get("Authorization") // this fakes a form
        c.ctx = getUser(c.ctx, c.db, authToken) // this also feels weird
        next.ServeHTTP(w, r)
    }

    return http.HandlerFunc(fn)
}

func (c *appContext)adminHandler(w http.ResponseWriter, r *http.Request) {
    defer c.cancel()
    user := c.ctx.Value(0).(user)
    json.NewEncoder(w).Encode(user)
}

func getUser(ctx context.Context, db *sql.DB, token string) context.Context{
    //this function mimics a database access
    return context.WithValue(ctx, 0, user{Nome:"Default user"})
}

func main() {
    db, err := sql.Open("my-driver", "my.db")
    if err != nil {
        panic(err)
    }
    ctx, cancel := context.WithCancel(context.Background())
    appC := appContext{db, ctx, cancel}
    //....
}
Run Code Online (Sandbox Code Playgroud)

一切正常,处理程序的加载速度比使用 gorilla/context 更快所以我的问题是:

  1. 这种方法安全吗?
  2. 真的有必要按照我的方式推迟 c.cancel() 函数吗?
  3. 我可以使用它来通过使用 struct 等控制器来与模型共享值来实现自定义 Web 框架吗?

Nic*_*uze 1

您的代码有问题,因为您将用户存储到应用程序上下文中。如果同时有多个用户,则不起作用。上下文必须与请求相关,以免被其他请求覆盖。用户必须存储在请求上下文中。在我的文章中,我使用以下大猩猩函数:context.Set(r, "user", user)r是请求。

如果你想context.Context在你的应用程序中使用,你应该使用他们的 gorilla 包装器(你可以在本文末尾找到它: https: //blog.golang.org/context)。

另外,您不需要取消上下文。context.Background()对于根上下文来说没问题。