douyouyi8878 2015-06-19 00:20
浏览 168
已采纳

正确使用go context.Context

I just read the article: Build You Own Web Framework In Go and for sharing values among handlers I picked the context.Context and I'm using it in the following way to share values across handlers and middlewares:

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

Everything is working and handlers are loading faster than using gorilla/context So my questions are:

  1. Is this approach safe?
  2. Is it really necessary to defer the c.cancel() function the way I'm doing it?
  3. Can I use it to implement a custom web framework by using controllers like struct to share values with models?
  • 写回答

2条回答 默认 最新

  • duanli0162 2015-06-19 05:02
    关注

    You have a problem with your code because you are storing the user into the app context. With multiple users at the same time, it doesn't work. The context must be related to the request to not be overwrote by other requests. The user must be stored in a request context. In my articles I use the following gorilla function: context.Set(r, "user", user). r is the request.

    If you want to use context.Context in your app, you should use their gorilla wrapper (you can find it at the end of this article: https://blog.golang.org/context).

    Also, you don't need a context with cancel. context.Background() is okay for the root context.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程