gohttphttp-redirectgo-gin

golang gin when to use handleContext and when redirect


Having processed a GET request, I want to redirect the user to a new URL, handled by my app, which displays the results.

In the gin documentation I found two different ways to do this. One is to use gin's redirect() function and the other is to use it's router HandleContext() function. The cited documentation says redirect() should be used for a POST request or for a GET request but then says HandleContext() should be used for a "Router" redirect. I'm not sure I fully understand the implications of using one or the other.

The first use case given in the documentation cited above is:

r.GET("/test", func(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})

What seems to be distinct here is that the redirecting is to an external URL, away from my app itself. The second use case, which is described as a 'Router redirect', is:

r.GET("/test", func(c *gin.Context) {
    c.Request.URL.Path = "/test2"
    r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
    c.JSON(200, gin.H{"hello": "world"})
})

So this seems to be required if the URL for the redirect is a path handled by my app.

But this is a URL like any other. So why not just use c.redirect() for Router redirects?

Intuitively, this is the obvious thing to do. But I suspect it produces unexpected behaviour (or at least, behaviour I personally didn't expect)

What's wrong with using c.redirect() for Router redirects, and what's the difference between it and router.HandleContext()?


Solution

  • The difference is that HandleContext() does an internal redirection that the client never notices, whereas Redirect() actually sends a response to the Http client notifying it, that the resource has changed.

    I think this can be best illustrated by observing the DevTools of a Browser.

    HandleContext(): HandleContext As you can see, here the client never even noticed that the request was redirected to another handler internally.

    Redirect(): redirect Here the client was forced to make two requests to get the actual resource. Also notice that the URL bar now displays the URL of the redirected request.

    Obviously making two requests leads to worse performance, which is why router.HandleContext() should be preferred for internal redirections.

    If you want to test yourself, here is the code:

    package main
    
    import (
        "net/http"
    
        "github.com/gin-gonic/gin"
    )
    
    func main() {
        r := gin.Default()
    
        // Switch the uncommented block in order to see the effect of HandleContext.
        /* r.GET("/test", func(c *gin.Context) {
            c.Request.URL.Path = "/test2"
            r.HandleContext(c)
        })
        r.GET("/test2", func(c *gin.Context) {
            c.JSON(200, gin.H{"hello": "world"})
        }) */
    
        r.GET("/test", func(c *gin.Context) {
            c.Redirect(http.StatusMovedPermanently, "/test2")
        })
        r.GET("/test2", func(c *gin.Context) {
            c.JSON(200, gin.H{"hello": "world"})
        })
    
        r.Run()
    }