Go gin框架CORS

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

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.Handlergin.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,

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.

huangapple
  • 本文由 发表于 2015年4月3日 01:03:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/29418478.html
匿名

发表评论

匿名网友

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

确定