Home > Back-end >  Golang Gin: Middleware with CORS not working
Golang Gin: Middleware with CORS not working

Time:05-09

I've got a POST request from my frontend app to my backend app written in Go using Gin. I was getting an error saying:

"No 'Access-Control-Allow-Origin' header is present on the requested resource"

so that pointed me to implement CORS in my backend app. So I did by using "github.com/gin-contrib/cors":

web.go:

func NewApp() *App {

    db := SetUpDB()
    router := gin.Default()

    router.Use(cors.New(cors.Config{
        //AllowOrigins:    []string{"http://localhost:3000", "http://127.0.0.1:3000"},
        AllowMethods:    []string{"PUT", "POST", "GET", "OPTIONS","DELETE"},
        AllowHeaders:    []string{"Origin"},
        AllowAllOrigins: true,
        //ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
        MaxAge:           12 * time.Hour,
    }))

    return &App{
        Db:     db,
        Router: router,
    }
}

and in main.go I've got:

app := core.NewApp()

    //app.Router.Use(CORS())

    defer func() {
        app.Db.Close()
        log.Printf("core: database stopping")
    }()

    app.Router.Use(func(c *gin.Context) {
        c.Set("db", app.Db)
    })

    app.Router.GET("/", func(ctx *gin.Context) {
        ctx.JSON(http.StatusOK, gin.H{"data": "welcome TEST"})
    })

    // Initialize all api routes
    routes.InitializeRoutes(app.Router.Group("/api/v1"))

as you can see I only set PUT in AllowMethods with the intention of testing CORS was actually working. By allowing only PUT I was expecting no methods other than PUT were allowed but I was wrong. I've performed a GET request from my frontend app and it goes through (it returns data), this leads me to think than the CORS implementation is not being picked up.

While browsing around, I've found people not using the package "github.com/gin-contrib/cors" but creating their own middleware:

func CORS() gin.HandlerFunc {
    return func(c *gin.Context) {

        fmt.Println(c.Request.Header)
        c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, Origin, Cache-Control, X-Requested-With")
        //c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "PUT, DELETE")

        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }

        c.Next()
    }
}

and then:

func NewApp() *App {

    db := SetUpDB()
    router := gin.Default()

    router.Use(CORS())

    return &App{
        Db:     db,
        Router: router,
    }
}

I tried this as well with no luck. Same results are coming back.

Furthermore, when I perform the GET and print the method in my backend (c.Request.Method) the result is GET. But when I perform a POST and print the method I'm getting OPTIONS

What am I missing? Why router is not using the provided middleware?

CodePudding user response:

The Access-Control-Allow-Methods header is only checked for CORS requests that cannot result from a Javascript-less HTML page (so-called non-simple requests). For simple requests such as GET with only standard headers, only the Access-Control-Allow-Origin header is checked and the Access-Control-Allow-Methods header plays no role.

CodePudding user response:

There are two pieces to this question:

  1. The first one was indicated above by Heiko: Get is a simple request so the result is always gonna be returned for these kind of requests.

  2. Now, after testing back my POST, I was still getting errors. I had checked over and over the CORS config, changing things here and there just to find out that the routes for Category were define such as:

categoryRouter.POST("/", controllers.CreateNewCategory)
categoryRouter.GET("/", controllers.ListAllCategories)

as you can see there is a trailing / which was causing my request to be redirected and an error to be returned since the url used for the request was http://127.0.0.1:8080/api/v1/categories. I updated the routes to be:

categoryRouter.POST("", controllers.CreateNewCategory)
categoryRouter.GET("", controllers.ListAllCategories)

and now it is working as expected.

  • Related