Go gin框架CORS

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

Go gin framework CORS

问题

我正在使用Go gin框架 gin

  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Writer.Header().Set("Content-Type", "application/json")
  4. c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
  5. c.Writer.Header().Set("Access-Control-Max-Age", "86400")
  6. c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
  7. c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max")
  8. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
  9. if c.Request.Method == "OPTIONS" {
  10. c.AbortWithStatus(200)
  11. } else {
  12. c.Next()
  13. }
  14. }
  15. }

我得到了状态码:200 OK,但在OPTIONS请求之后没有任何反应。
看起来我漏掉了一些东西,但我不知道我错在哪里。

有人可以帮帮我吗?

英文:

I'm using Go gin framework gin

  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Writer.Header().Set("Content-Type", "application/json")
  4. c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
  5. c.Writer.Header().Set("Access-Control-Max-Age", "86400")
  6. c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
  7. c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max")
  8. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
  9. if c.Request.Method == "OPTIONS" {
  10. c.AbortWithStatus(200)
  11. } else {
  12. c.Next()
  13. }
  14. }
  15. }

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中间件,适用于我的需求。

  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
  4. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
  5. 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")
  6. c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
  7. if c.Request.Method == "OPTIONS" {
  8. c.AbortWithStatus(204)
  9. return
  10. }
  11. c.Next()
  12. }
  13. }

这段代码是一个用于处理CORS的中间件,它设置了允许的来源、允许的请求头、允许的方法等。如果请求的方法是OPTIONS,它会返回状态码204并终止请求。否则,它会继续处理请求。

英文:

FWIW, this is my CORS Middleware that works for my needs.

  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
  4. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
  5. 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")
  6. c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
  7. if c.Request.Method == "OPTIONS" {
  8. c.AbortWithStatus(204)
  9. return
  10. }
  11. c.Next()
  12. }
  13. }

答案2

得分: 28

还有官方的gin中间件可以处理CORS请求github.com/gin-contrib/cors

你可以使用$ go get github.com/gin-contrib/cors进行安装,然后在你的应用程序中添加这个中间件,像这样:

  1. package main
  2. import (
  3. "time"
  4. "github.com/gin-contrib/cors"
  5. "github.com/gin-gonic/gin"
  6. )
  7. func main() {
  8. router := gin.Default()
  9. // CORS for https://foo.com and https://github.com origins, allowing:
  10. // - PUT and PATCH methods
  11. // - Origin header
  12. // - Credentials share
  13. // - Preflight requests cached for 12 hours
  14. router.Use(cors.New(cors.Config{
  15. AllowOrigins: []string{"https://foo.com"},
  16. AllowMethods: []string{"PUT", "PATCH"},
  17. AllowHeaders: []string{"Origin"},
  18. ExposeHeaders: []string{"Content-Length"},
  19. AllowCredentials: true,
  20. AllowOriginFunc: func(origin string) bool {
  21. return origin == "https://github.com"
  22. },
  23. MaxAge: 12 * time.Hour,
  24. }))
  25. router.Run()
  26. }
英文:

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

  1. import (
  2. "time"
  3. "github.com/gin-contrib/cors"
  4. "github.com/gin-gonic/gin"
  5. )
  6. func main() {
  7. router := gin.Default()
  8. // CORS for https://foo.com and https://github.com origins, allowing:
  9. // - PUT and PATCH methods
  10. // - Origin header
  11. // - Credentials share
  12. // - Preflight requests cached for 12 hours
  13. router.Use(cors.New(cors.Config{
  14. AllowOrigins: []string{"https://foo.com"},
  15. AllowMethods: []string{"PUT", "PATCH"},
  16. AllowHeaders: []string{"Origin"},
  17. ExposeHeaders: []string{"Content-Length"},
  18. AllowCredentials: true,
  19. AllowOriginFunc: func(origin string) bool {
  20. return origin == "https://github.com"
  21. },
  22. MaxAge: 12 * time.Hour,
  23. }))
  24. router.Run()
  25. }

答案3

得分: 13

  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Header("Access-Control-Allow-Origin", "*")
  4. c.Header("Access-Control-Allow-Credentials", "true")
  5. c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
  6. c.Header("Access-Control-Allow-Methods", "POST,HEAD,PATCH, OPTIONS, GET, PUT")
  7. if c.Request.Method == "OPTIONS" {
  8. c.AbortWithStatus(204)
  9. return
  10. }
  11. c.Next()
  12. }
  13. }

然后在代码中使用它:

  1. router = gin.New()
  2. router.Use(CORSMiddleware())
英文:
  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Header("Access-Control-Allow-Origin", "*")
  4. c.Header("Access-Control-Allow-Credentials", "true")
  5. c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
  6. c.Header("Access-Control-Allow-Methods", "POST,HEAD,PATCH, OPTIONS, GET, PUT")
  7. if c.Request.Method == "OPTIONS" {
  8. c.AbortWithStatus(204)
  9. return
  10. }
  11. c.Next()
  12. }
  13. }

then use it

  1. router = gin.New()
  2. router.Use(CORSMiddleware())

答案4

得分: 13

我花了大约一个小时才明白为什么有些来自互联网的示例可以工作,而有些则不行。所以我找到了区别 - 行的顺序很重要,首先你应该使用配置,然后再声明你的端点,而不是相反的方式。

可以工作的示例:

  1. router := gin.Default()
  2. router.Use(cors.Default())
  3. router.GET("/ping", pong)
  4. router.Run(":8082")

不工作的示例:

  1. router := gin.Default()
  2. router.GET("/ping", pong)
  3. router.Use(cors.Default())
  4. 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:

  1. router := gin.Default()
  2. router.Use(cors.Default())
  3. router.GET("/ping", pong)
  4. router.Run(":8082")

Doesn't work:

  1. router := gin.Default()
  2. router.GET("/ping", pong)
  3. router.Use(cors.Default())
  4. router.Run(":8082")

答案5

得分: 4

这是一个处理CORS请求的包https://github.com/rs/cors,它以正确的方式处理CORS请求。它提供了一些示例,适用于包括gin在内的流行路由器。示例代码如下:

  1. package main
  2. import (
  3. "net/http"
  4. "github.com/gin-gonic/gin"
  5. cors "github.com/rs/cors/wrapper/gin"
  6. )
  7. func main() {
  8. router := gin.Default()
  9. router.Use(cors.Default())
  10. router.GET("/", func(context *gin.Context) {
  11. context.JSON(http.StatusOK, gin.H{"hello": "world"})
  12. })
  13. router.Run(":8080")
  14. }

通常情况下,你只需要在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:

  1. package main
  2. import (
  3. "net/http"
  4. "github.com/gin-gonic/gin"
  5. cors "github.com/rs/cors/wrapper/gin"
  6. )
  7. func main() {
  8. router := gin.Default()
  9. router.Use(cors.Default())
  10. router.GET("/", func(context *gin.Context) {
  11. context.JSON(http.StatusOK, gin.H{"hello": "world"})
  12. })
  13. router.Run(":8080")
  14. }

In common case, you just add the default handling with router.Use(cors.Default()) to your middlewares in gin. It is enough.

答案6

得分: 3

我们创建了一个最小的中间件。

  1. import (
  2. "github.com/gin-gonic/gin"
  3. "net/http"
  4. )
  5. type optionsMiddleware struct {
  6. }
  7. func CreateOptionsMiddleware() *optionsMiddleware{
  8. return &optionsMiddleware{}
  9. }
  10. func (middleware *optionsMiddleware)Response(context *gin.Context){
  11. if context.Request.Method == "OPTIONS" {
  12. context.AbortWithStatus(http.StatusNoContent)
  13. }
  14. }

并将其注册到gin中间件中:

  1. app := gin.New()
  2. app.Use(middleware.CreateOptionsMiddleware().Response).
  3. Use(next-middleware)......
英文:

We created a minimal middleware.

  1. import (
  2. "github.com/gin-gonic/gin"
  3. "net/http"
  4. )
  5. type optionsMiddleware struct {
  6. }
  7. func CreateOptionsMiddleware() *optionsMiddleware{
  8. return &optionsMiddleware{}
  9. }
  10. func (middleware *optionsMiddleware)Response(context *gin.Context){
  11. if context.Request.Method == "OPTIONS" {
  12. context.AbortWithStatus(http.StatusNoContent)
  13. }
  14. }

and register it with gin middleware :

  1. app := gin.New()
  2. app.Use(middleware.CreateOptionsMiddleware().Response).
  3. 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提供的适配器:

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "github.com/gin-gonic/gin"
  6. adapter "github.com/gwatts/gin-adapter"
  7. "github.com/jub0bs/fcors"
  8. )
  9. func main() {
  10. // 创建一个引擎
  11. engine := gin.Default()
  12. // 配置CORS中间件
  13. cors, err := fcors.AllowAccess(
  14. fcors.FromAnyOrigin(),
  15. fcors.WithMethods(
  16. http.MethodGet,
  17. http.MethodPost,
  18. http.MethodPut,
  19. http.MethodDelete,
  20. "UPDATE",
  21. ),
  22. fcors.WithRequestHeaders(
  23. "Authorization",
  24. "Content-Type",
  25. "X-CSRF-Token",
  26. "X-Max",
  27. ),
  28. fcors.MaxAgeInSeconds(86400),
  29. )
  30. if err != nil {
  31. log.Fatal(err)
  32. }
  33. // 将CORS中间件应用到引擎
  34. engine.Use(adapter.Wrap(cors))
  35. // 为/hello路由注册hello处理程序
  36. engine.GET("/hello", hello)
  37. // 在端口8080上启动服务器
  38. if err := engine.Run(":8080"); err != nil {
  39. log.Fatal(err)
  40. }
  41. }
  42. func hello(ctx *gin.Context) {
  43. ctx.JSON(http.StatusOK, gin.H{"hello": "world"})
  44. }
英文:

> 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:

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "github.com/gin-gonic/gin"
  6. adapter "github.com/gwatts/gin-adapter"
  7. "github.com/jub0bs/fcors"
  8. )
  9. func main() {
  10. // create an engine
  11. engine := gin.Default()
  12. // configure the CORS middleware
  13. cors, err := fcors.AllowAccess(
  14. fcors.FromAnyOrigin(),
  15. fcors.WithMethods(
  16. http.MethodGet,
  17. http.MethodPost,
  18. http.MethodPut,
  19. http.MethodDelete,
  20. "UPDATE",
  21. ),
  22. fcors.WithRequestHeaders(
  23. "Authorization",
  24. "Content-Type",
  25. "X-CSRF-Token",
  26. "X-Max",
  27. ),
  28. fcors.MaxAgeInSeconds(86400),
  29. )
  30. if err != nil {
  31. log.Fatal(err)
  32. }
  33. // apply the CORS middleware to the engine
  34. engine.Use(adapter.Wrap(cors))
  35. // register the hello handler for the /hello route
  36. engine.GET("/hello", hello)
  37. // start the server on port 8080
  38. if err := engine.Run(":8080"); err != nil {
  39. log.Fatal(err)
  40. }
  41. }
  42. func hello(ctx *gin.Context) {
  43. ctx.JSON(http.StatusOK, gin.H{"hello": "world"})
  44. }

答案8

得分: 2

这对我有用-注意:直接设置头部。

  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Header("Access-Control-Allow-Origin", "*")
  4. c.Header("Access-Control-Allow-Headers", "*")
  5. /*
  6. c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
  7. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
  8. c.Writer.Header().Set("Access-Control-Allow-Headers", "access-control-allow-origin, access-control-allow-headers")
  9. c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH")
  10. */
  11. if c.Request.Method == "OPTIONS" {
  12. c.AbortWithStatus(204)
  13. return
  14. }
  15. c.Next()
  16. }
  17. }
英文:

This worked for me - NOTE: the setting of header directly.

  1. func CORSMiddleware() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. c.Header("Access-Control-Allow-Origin", "*")
  4. c.Header("Access-Control-Allow-Headers", "*")
  5. /*
  6. c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
  7. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
  8. c.Writer.Header().Set("Access-Control-Allow-Headers", "access-control-allow-origin, access-control-allow-headers")
  9. c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH")
  10. */
  11. if c.Request.Method == "OPTIONS" {
  12. c.AbortWithStatus(204)
  13. return
  14. }
  15. c.Next()
  16. }
  17. }

答案9

得分: 2

使用gin-contrib/cors

  1. import "github.com/gin-contrib/cors"
  2. [...]
  3. router.Use(cors.New(cors.Config{
  4. AllowOrigins: []string{"http://localhost:4040"},
  5. AllowMethods: []string{"GET"},
  6. AllowHeaders: []string{"Content-Type", "Content-Length", "Accept-Encoding", "Authorization", "Cache-Control"},
  7. ExposeHeaders: []string{"Content-Length"},
  8. AllowCredentials: true,
  9. MaxAge: 12 * time.Hour,
  10. }))

在我的情况下,我在这个中间件之前有一个JWT令牌中间件,它阻止了所有的OPTION预检请求。将CORS中间件放在前面解决了这个问题。

英文:

With gin-contrib/cors

  1. import "github.com/gin-contrib/cors"
  2. [...]
  3. router.Use(cors.New(cors.Config{
  4. AllowOrigins: []string{"http://localhost:4040"},
  5. AllowMethods: []string{"GET"},
  6. AllowHeaders: []string{"Content-Type", "Content-Length", "Accept-Encoding", "Authorization", "Cache-Control"},
  7. ExposeHeaders: []string{"Content-Length"},
  8. AllowCredentials: true,
  9. MaxAge: 12 * time.Hour,
  10. }))

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:

确定