英文:
Go gin framework CORS
问题
我正在使用Go gin框架 gin
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Content-Type", "application/json")
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Max-Age", "86400")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(200)
} else {
c.Next()
}
}
}
我得到了状态码:200 OK,但在OPTIONS请求之后没有任何反应。
看起来我漏掉了一些东西,但我不知道我错在哪里。
有人可以帮帮我吗?
英文:
I'm using Go gin framework gin
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Content-Type", "application/json")
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Max-Age", "86400")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(200)
} else {
c.Next()
}
}
}
I've got Status Code:200 OK, but nothing happens after OPTIONS request.
It looks like I miss something, but I can't understand where am I wrong.
Can anybody help me?
答案1
得分: 94
这是我的CORS中间件,适用于我的需求。
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
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")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
这段代码是一个用于处理CORS的中间件,它设置了允许的来源、允许的请求头、允许的方法等。如果请求的方法是OPTIONS,它会返回状态码204并终止请求。否则,它会继续处理请求。
英文:
FWIW, this is my CORS Middleware that works for my needs.
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
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")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
答案2
得分: 28
还有官方的gin中间件可以处理CORS请求github.com/gin-contrib/cors。
你可以使用$ go get github.com/gin-contrib/cors
进行安装,然后在你的应用程序中添加这个中间件,像这样:
package main
import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// CORS for https://foo.com and https://github.com origins, allowing:
// - PUT and PATCH methods
// - Origin header
// - Credentials share
// - Preflight requests cached for 12 hours
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://foo.com"},
AllowMethods: []string{"PUT", "PATCH"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
AllowOriginFunc: func(origin string) bool {
return origin == "https://github.com"
},
MaxAge: 12 * time.Hour,
}))
router.Run()
}
英文:
There is also official gin's middleware for handling CORS requests github.com/gin-contrib/cors.
You could install it using $ go get github.com/gin-contrib/cors
and then add this middleware in your application like this:
package main
import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// CORS for https://foo.com and https://github.com origins, allowing:
// - PUT and PATCH methods
// - Origin header
// - Credentials share
// - Preflight requests cached for 12 hours
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://foo.com"},
AllowMethods: []string{"PUT", "PATCH"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
AllowOriginFunc: func(origin string) bool {
return origin == "https://github.com"
},
MaxAge: 12 * time.Hour,
}))
router.Run()
}
答案3
得分: 13
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Credentials", "true")
c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Header("Access-Control-Allow-Methods", "POST,HEAD,PATCH, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
然后在代码中使用它:
router = gin.New()
router.Use(CORSMiddleware())
英文:
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Credentials", "true")
c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Header("Access-Control-Allow-Methods", "POST,HEAD,PATCH, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
then use it
router = gin.New()
router.Use(CORSMiddleware())
答案4
得分: 13
我花了大约一个小时才明白为什么有些来自互联网的示例可以工作,而有些则不行。所以我找到了区别 - 行的顺序很重要,首先你应该使用配置,然后再声明你的端点,而不是相反的方式。
可以工作的示例:
router := gin.Default()
router.Use(cors.Default())
router.GET("/ping", pong)
router.Run(":8082")
不工作的示例:
router := gin.Default()
router.GET("/ping", pong)
router.Use(cors.Default())
router.Run(":8082")
英文:
I spent like an hour to get why some example from the internet works, and some doesn't. So I got the difference - line order is important, fristly you should use config and then declare your endpoints, but not the opposite way.
Works:
router := gin.Default()
router.Use(cors.Default())
router.GET("/ping", pong)
router.Run(":8082")
Doesn't work:
router := gin.Default()
router.GET("/ping", pong)
router.Use(cors.Default())
router.Run(":8082")
答案5
得分: 4
这是一个处理CORS请求的包https://github.com/rs/cors,它以正确的方式处理CORS请求。它提供了一些示例,适用于包括gin
在内的流行路由器。示例代码如下:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
cors "github.com/rs/cors/wrapper/gin"
)
func main() {
router := gin.Default()
router.Use(cors.Default())
router.GET("/", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{"hello": "world"})
})
router.Run(":8080")
}
通常情况下,你只需要在gin
的中间件中添加router.Use(cors.Default())
来处理CORS请求,默认设置已经足够了。
英文:
There is package https://github.com/rs/cors, that handles CORS requests in the right way. It has the examples for the popular routers including gin
. That it:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
cors "github.com/rs/cors/wrapper/gin"
)
func main() {
router := gin.Default()
router.Use(cors.Default())
router.GET("/", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{"hello": "world"})
})
router.Run(":8080")
}
In common case, you just add the default handling with router.Use(cors.Default())
to your middlewares in gin
. It is enough.
答案6
得分: 3
我们创建了一个最小的中间件。
import (
"github.com/gin-gonic/gin"
"net/http"
)
type optionsMiddleware struct {
}
func CreateOptionsMiddleware() *optionsMiddleware{
return &optionsMiddleware{}
}
func (middleware *optionsMiddleware)Response(context *gin.Context){
if context.Request.Method == "OPTIONS" {
context.AbortWithStatus(http.StatusNoContent)
}
}
并将其注册到gin中间件中:
app := gin.New()
app.Use(middleware.CreateOptionsMiddleware().Response).
Use(next-middleware)......
英文:
We created a minimal middleware.
import (
"github.com/gin-gonic/gin"
"net/http"
)
type optionsMiddleware struct {
}
func CreateOptionsMiddleware() *optionsMiddleware{
return &optionsMiddleware{}
}
func (middleware *optionsMiddleware)Response(context *gin.Context){
if context.Request.Method == "OPTIONS" {
context.AbortWithStatus(http.StatusNoContent)
}
}
and register it with gin middleware :
app := gin.New()
app.Use(middleware.CreateOptionsMiddleware().Response).
Use(next-middleware)......
答案7
得分: 3
看起来我错过了一些东西,但我不明白我错在哪里。
因为CORS协议比表面上看起来更复杂,通过“手动”设置CORS响应头来实现它容易出错。在这种特定情况下,
- 你可能遇到了所谓的“通配符异常”,它不允许在带凭据的请求中使用通配符(
*
); - 你还试图允许Fetch标准将其归类为“禁止”的请求头,但浏览器会默默地忽略客户端在请求中包含此类头的尝试。
这些困难可能足以让你相信,总的来说,你最好依赖一个好的CORS中间件库,它可以将所有这些复杂性抽象化。
Gin确实有一个官方的CORS中间件库:gin-contrib/cors,但它远非理想;我在最近的一篇博文中详细讨论了这个主题。如果gin-contrib/cors让你不满意,也许你会喜欢我自己的CORS中间件库:jub0bs/fcors。它旨在不仅更易于使用,而且更难被误用。
它主要与http.Handler
兼容,但可以通过http.Handler
到gin.HandleFunc
适配器与Gin一起使用,例如由gwatts/gin-adapter提供的适配器:
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
adapter "github.com/gwatts/gin-adapter"
"github.com/jub0bs/fcors"
)
func main() {
// 创建一个引擎
engine := gin.Default()
// 配置CORS中间件
cors, err := fcors.AllowAccess(
fcors.FromAnyOrigin(),
fcors.WithMethods(
http.MethodGet,
http.MethodPost,
http.MethodPut,
http.MethodDelete,
"UPDATE",
),
fcors.WithRequestHeaders(
"Authorization",
"Content-Type",
"X-CSRF-Token",
"X-Max",
),
fcors.MaxAgeInSeconds(86400),
)
if err != nil {
log.Fatal(err)
}
// 将CORS中间件应用到引擎
engine.Use(adapter.Wrap(cors))
// 为/hello路由注册hello处理程序
engine.GET("/hello", hello)
// 在端口8080上启动服务器
if err := engine.Run(":8080"); err != nil {
log.Fatal(err)
}
}
func hello(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"hello": "world"})
}
英文:
> It looks like I miss something, but I can't understand where am I wrong.
Because CORS is more complex a protocol than meets the eye, implementing it by "manually" setting CORS response headers is error-prone. In this specific case,
- you've likely hit the so-called wildcard exception, which disallows the use of the wildcard (
*
) in conjunction with credentialed requests; - you're also attempting to allow request headers that the Fetch standard categorises as forbidden, but browsers silently ignore client attempts to include such headers in requests.
These difficulties may be enough to convince you that, in general, you're better off relying on a good CORS middleware library, which can abstract all this complexity away from you.
Gin does have an official CORS middleware library: gin-contrib/cors, but it's far from ideal; I've written at length about this topic in a recent blog post. If gin-contrib/cors leaves you dissatisfied, perhaps you'll appreciate my own CORS middleware library: jub0bs/fcors. It's designed to be, not only easier to use, but also harder to misuse.
It's primarily compatible with http.Handler
, but it can be used in conjunction with Gin via a http.Handler
-to-gin.HandleFunc
adapter, such as that provided by gwatts/gin-adapter:
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
adapter "github.com/gwatts/gin-adapter"
"github.com/jub0bs/fcors"
)
func main() {
// create an engine
engine := gin.Default()
// configure the CORS middleware
cors, err := fcors.AllowAccess(
fcors.FromAnyOrigin(),
fcors.WithMethods(
http.MethodGet,
http.MethodPost,
http.MethodPut,
http.MethodDelete,
"UPDATE",
),
fcors.WithRequestHeaders(
"Authorization",
"Content-Type",
"X-CSRF-Token",
"X-Max",
),
fcors.MaxAgeInSeconds(86400),
)
if err != nil {
log.Fatal(err)
}
// apply the CORS middleware to the engine
engine.Use(adapter.Wrap(cors))
// register the hello handler for the /hello route
engine.GET("/hello", hello)
// start the server on port 8080
if err := engine.Run(":8080"); err != nil {
log.Fatal(err)
}
}
func hello(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"hello": "world"})
}
答案8
得分: 2
这对我有用-注意:直接设置头部。
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Headers", "*")
/*
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", "access-control-allow-origin, access-control-allow-headers")
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH")
*/
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
英文:
This worked for me - NOTE: the setting of header directly.
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Headers", "*")
/*
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", "access-control-allow-origin, access-control-allow-headers")
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH")
*/
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
答案9
得分: 2
使用gin-contrib/cors
import "github.com/gin-contrib/cors"
[...]
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:4040"},
AllowMethods: []string{"GET"},
AllowHeaders: []string{"Content-Type", "Content-Length", "Accept-Encoding", "Authorization", "Cache-Control"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
在我的情况下,我在这个中间件之前有一个JWT令牌中间件,它阻止了所有的OPTION预检请求。将CORS中间件放在前面解决了这个问题。
英文:
With gin-contrib/cors
import "github.com/gin-contrib/cors"
[...]
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:4040"},
AllowMethods: []string{"GET"},
AllowHeaders: []string{"Content-Type", "Content-Length", "Accept-Encoding", "Authorization", "Cache-Control"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
In my case, I had a JWT token middleware before this one that blocked all OPTION pre-flight requests. Putting the CORS middleware first solved the problem.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论