如何使用Gin Web框架将参数传递给Golang中的路由器处理程序?

Nik*_*as9 16 go go-gin

我正在使用Gin,https: //gin-gonic.github.io/gin/,用Golang构建一个简单的RESTful JSON API.

路线设置如下:

func testRouteHandler(c *gin.Context) {
    // do smth
}

func main() {
    router := gin.Default()
    router.GET("/test", testRouteHandler)
    router.Run(":8080")
}
Run Code Online (Sandbox Code Playgroud)

我的问题是如何将参数传递给testRouteHandler函数?例如,公共数据库连接可能是想要在路由之间重用的东西.

在全局变量中使用它的最佳方法是什么?或者Go中有一些方法可以将额外的变量传递给testRouteHandler函数吗?Go中的函数是否有可选参数?

PS.我刚刚开始学习Go,所以可能是一些我很想念的东西:)

eli*_*rar 22

我会避免将"应用程序作用域"依赖项(例如数据库连接池)填充到请求上下文中.你最简单的两个选择是:

  1. 让它成为全球性的.对于较小的项目,这是可以的,并且*sql.DB是线程安全的.
  2. 在闭包中显式传递它,以便返回类型满足 gin.HandlerFunc

例如

// SomeHandler returns a `func(*gin.Context)` to satisfy Gin's router methods
// db could turn into an 'Env' struct that encapsulates all of your
// app dependencies - e.g. DB, logger, env vars, etc.
func SomeHandler(db *sql.DB) gin.HandlerFunc {
    fn := func(c *gin.Context) {
        // Your handler code goes in here - e.g.
        rows, err := db.Query(...)

        c.String(200, results)
    }

    return gin.HandlerFunc(fn)
}

func main() {
    db, err := sql.Open(...)
    // handle the error

    router := gin.Default()
    router.GET("/test", SomeHandler(db))
    router.Run(":8080")
}
Run Code Online (Sandbox Code Playgroud)


rcm*_*ite 19

使用我在评论上发布的链接,我创建了一个简单的例子.

package main

import (
    "log"

    "github.com/gin-gonic/gin"
    "github.com/jinzhu/gorm"
    _ "github.com/mattn/go-sqlite3"
)

// ApiMiddleware will add the db connection to the context
func ApiMiddleware(db gorm.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Set("databaseConn", db)
        c.Next()
    }
}

func main() {
    r := gin.New()

    // In this example, I'll open the db connection here...
    // In your code you would probably do it somewhere else
    db, err := gorm.Open("sqlite3", "./example.db")
    if err != nil {
        log.Fatal(err)
    }

    r.Use(ApiMiddleware(db))

    r.GET("/api", func(c *gin.Context) {
        // Don't forget type assertion when getting the connection from context.
        dbConn, ok := c.MustGet("databaseConn").(gorm.DB)
        if !ok {
            // handle error here...
        }

        // do your thing here...
    })

    r.Run(":8080")
}
Run Code Online (Sandbox Code Playgroud)

这只是一个简单的POC.但我相信这是一个开始.希望能帮助到你.

  • 不幸的是,这是最好的答案。这并不理想,因为“Set”和“Get”创建了依赖关系,其中闭包模式可以简单地将参数从中间件传递到封闭的路由。然而,Gin 并不自然地使用闭包模式,因此像 `Use` 和 `Group` 这样的一些方法变得复杂。 (2认同)

小智 8

Late to the party, so far here is my proposal. Encapsulate methods into the object with private/public vars in it:

package main

import (
    "log"

    "github.com/gin-gonic/gin"
    "github.com/jinzhu/gorm"
    _ "github.com/mattn/go-sqlite3"
)

type HandlerA struct {
    Db gorm.DB
}

func (this *HandlerA) Get(c *gin.Context) {

    log.Info("[%#f]", this.Db)
    // do your thing here...
}

func main() {
    r := gin.New()

    // Init, should be separate, but it's ok for this sample:
    db, err := gorm.Open("sqlite3", "./example.db")
    if err != nil {
        log.Fatal(err)
    }

    Obj := new(HandlerA)
    Obj.Db = db // Or init inside Object

    r := gin.New()

    Group := r.Group("api/v1/")
    {
        Group.GET("/storage", Obj.Get)
    }

    r.Run(":8080")
}
Run Code Online (Sandbox Code Playgroud)