Golang Gin:CORS中间件不起作用。

huangapple go评论81阅读模式
英文:

Golang Gin: Middleware with CORS not working

问题

我从前端应用收到了一个POST请求,该请求发送到了使用Gin编写的后端应用中。我遇到了一个错误:

> "请求的资源上没有'Access-Control-Allow-Origin'头"

这提示我在后端应用中实现CORS。所以我使用了"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,
	}
}

main.go中:

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"))

你可以看到,我只在AllowMethods中设置了PUT,目的是为了测试CORS是否有效。我期望只有PUT方法被允许,但事实证明我错了。我从前端应用执行了一个GET请求,它通过了(返回了数据),这让我认为CORS实现没有生效。

在浏览过程中,我发现有些人没有使用"github.com/gin-contrib/cors"包,而是创建了自己的中间件:

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()
	}
}

然后:

func NewApp() *App {

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

	router.Use(CORS())

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

我也尝试了这个方法,但没有成功。结果还是一样。

此外,当我执行GET并打印后端的方法(c.Request.Method)时,结果是GET。但当我执行POST并打印方法时,我得到的是OPTIONS

我漏掉了什么?为什么router没有使用提供的中间件?

英文:

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?

答案1

得分: 2

这个问题有两个部分:

  1. 第一个部分已经被Heiko指出了:GET是一个简单的请求,所以结果总是会返回这种类型的请求。

  2. 现在,在测试我的POST请求后,我仍然遇到了错误。我一遍又一遍地检查了CORS配置,改变了一些东西,只是为了发现Category的路由定义如下:

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

你可以看到有一个尾随的/,这导致我的请求被重定向,并返回一个错误,因为请求使用的URL是http://127.0.0.1:8080/api/v1/categories。我更新了路由如下:

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

现在它按预期工作了。

英文:

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.

答案2

得分: 1

Access-Control-Allow-Methods 头部仅在跨域请求中进行检查,这些请求不会由无 JavaScript 的 HTML 页面(也称为非简单请求)生成。对于只包含标准头部的简单请求,例如仅有 GET 方法的请求,只会检查 Access-Control-Allow-Origin 头部,而 Access-Control-Allow-Methods 头部不起作用。

英文:

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.

huangapple
  • 本文由 发表于 2022年5月8日 02:07:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/72155224.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定