gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
77.85k stars 7.96k forks source link

Cannot set cookies in goroutine #1587

Open kiura24metrics opened 5 years ago

kiura24metrics commented 5 years ago

Description

In readme file it states that one must use a read-only copy of gin.Context in goroutines but in this case I cannot set cookie since there is no ResponseWriter in read-only copy of gin.Context. and it panics: panic: runtime error: invalid memory address or nil pointer dereference

If I use original context then it throws fatal error: concurrent map writes.

So the question is how to accomplish this properly?

sairoutine commented 5 years ago

You can not set cookies in the goroutine. This is because it is asynchronous and the user's request is completed before the cookie header is set.

You should wait for the goroutine and set cookies outside the goroutine.

Example

package main

import (
    "fmt"

    "github.com/gin-gonic/gin"
)

func main() {

    router := gin.Default()

    router.GET("/cookie", func(c *gin.Context) {
        cookie := ""
        ch := make(chan bool)
        go func() {
            cookie = "set_in_the_goroutine" // generate only the cookie variable
            ch <- true
        }()

        // wait for the goroutine
        <-ch

        // set cookie outside the goroutine
        c.SetCookie("gin_cookie", cookie, 3600, "/", "localhost", false, true)
        fmt.Printf("Cookie value: %s \n", cookie)
    })

    router.Run()
}
kiura24metrics commented 5 years ago

I see, I wanted to set cookie in the goroutine (even though I wait for it to finish in the main loop before the user's request is completed). The system we are building is really complex, so it would be much easier to be able to set it in the goroutine (since we are waiting for it to finish anyways).