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
78.27k stars 7.99k forks source link

Why is the redirect executed twice #3640

Open Victoryship opened 1 year ago

Victoryship commented 1 year ago

Description

I ran into this problem while testing implementing internal redirects

How to reproduce

package main

import (
    "fmt"
    "net/http"

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

func Middleware1() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("Middleware 1 - Before")

        // Call the next middleware
        c.Next()

        fmt.Println("Middleware 1 - After")

    }
}

func Middleware2() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("Middleware 2 - Before")
        c.Next()
        // Continue executing the remaining middleware or handler logic
        fmt.Println("Middleware 2 - After")
    }
}

func Middleware3() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("Middleware 3 - Before")
        c.Next()
        // Continue executing the remaining middleware or handler logic
        fmt.Println("Middleware 3 - After")
    }
}

func Middleware4() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("Middleware 4 - Before")
        c.Next()
        // Continue executing the remaining middleware or handler logic
        fmt.Println("Middleware 4 - After")
    }
}

func FinalHandler(c *gin.Context) {
    fmt.Println("Final Handler")
    c.String(http.StatusOK, "Response from final handler")
}

func main() {
    router := gin.Default()
    v1 := router.Group("/api")
    {
        v1.Use(Middleware1(), Middleware2(), Middleware3(), Middleware4())
        v1.GET("/test", FinalHandler)
    }
    v2 := router.Group("/router")
    {
        v2.GET("/index", func(c *gin.Context) {
            fmt.Println("改写")
            c.Request.URL.Path = "/api/test"
        }, func(c *gin.Context) {
            fmt.Println("重入")
            router.HandleContext(c)
        })
    }
    router.Run(":8080")
}

Expectations

企业微信截图_16861230451226

Actual result

企业微信截图_16861204712794

Environment

Victoryship commented 1 year ago
func main() {
    router := gin.Default()
    v1 := router.Group("/api")
    {
        v1.Use(Middleware1(), Middleware2(), Middleware3(), Middleware4())
        v1.GET("/test", FinalHandler)
    }
    v2 := router.Group("/router")
    {
        v2.GET("/index", func(c *gin.Context) {
            fmt.Println("改写")
            c.Request.URL.Path = "/api/test"
            c.Abort()
            router.HandleContext(c)
        })
    }
    router.Run(":8080")
}

I can rewrite it like this, but I don't know why

YuukanOO commented 1 year ago

Hi @Victoryship, as per https://jastorey.me/blog/request-rewrite-in-gin.html, your rewrite works because you're cancelling the initial context handling with c.Abort() to make sure the response buffer is not written twice.

Victoryship commented 1 year ago

Thank you @YuukanOO for answering,I check the source code here to see if it should be modified 企业微信截图_16861319815091 that don't need abort