英文:
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
这个问题有两个部分:
-
第一个部分已经被Heiko指出了:GET是一个简单的请求,所以结果总是会返回这种类型的请求。
-
现在,在测试我的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:
-
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.
-
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论