安装
go get -u github.com/gin-gonic/gin
package mainimport ( "net/http" "github.com/gin-gonic/gin")func pong(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", })}func main() { //实例化一个gin的server对象 r := gin.Default() r.GET("/ping", pong) r.Run(":8083") // listen and serve on 0.0.0.0:8080}
使用get、post、put等http方法
func main() { // 使用默认中间件创建一个gin路由器 // logger(打印日志) and recovery (crash-free) 中间件 router := gin.Default() //router := gin.New()去掉了上面两个中间件 router.GET("/someGet", getting) router.POST("/somePost", posting) router.PUT("/somePut", putting) router.DELETE("/someDelete", deleting) router.PATCH("/somePatch", patching) router.HEAD("/someHead", head) router.OPTIONS("/someOptions", options) // 默认启动的是 8080端口,也可以自己定义启动端口 router.Run() // router.Run(":3000") for a hard coded port}
url和路由分组
func main() { router := gin.Default() // Simple group: v1 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) v1.POST("/read", readEndpoint) } // Simple group: v2 v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) } router.Run(":8082")}
带参数的url
package mainimport ( "github.com/gin-gonic/gin" "net/http")func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.GET("/user/:name/:action/", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") c.String(http.StatusOK, "%s is %s", name, action) }) r.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") c.String(http.StatusOK, "%s is %s", name, action) }) r.Run(":8082") }
获取路由分组的参数
package mainimport "github.com/gin-gonic/gin"type Person struct { ID string `uri:"id" binding:"required,uuid"` Name string `uri:"name" binding:"required"`}func main() { route := gin.Default() route.GET("/:name/:id", func(c *gin.Context) { var person Person if err := c.ShouldBindUri(&person); err != nil { c.JSON(400, gin.H{"msg": err}) return } c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID}) }) route.Run(":8088")}
获取参数
func main() { router := gin.Default() //url中添加值,在?后面 // 匹配的url格式: /welcome?firstname=Jane&lastname=Doe router.GET("/welcome", func(c *gin.Context) { firstname := c.DefaultQuery("firstname", "Guest")//获取firstname的值,没有值就得默认值 lastname := c.Query("lastname") // 是 c.Request.URL.Query().Get("lastname") 的简写 c.String(http.StatusOK, "Hello %s %s", firstname, lastname) }) router.Run(":8080")}
func main() { router := gin.Default() router.POST("/form_post", func(c *gin.Context) { message := c.PostForm("message")//url中是Query,post是PostForm nick := c.DefaultPostForm("nick", "anonymous") // 此方法可以设置默认值 c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) }) router.Run(":8080")}
POST /post?id=1234&page=1 HTTP/1.1Content-Type: application/x-www-form-urlencodedname=manu&message=this_is_greatfunc main() { router := gin.Default() router.POST("/post", func(c *gin.Context) { id := c.Query("id")//获取的是url中的参数 page := c.DefaultQuery("page", "0") name := c.PostForm("name")//获取的是表单中的参数 message := c.PostForm("message") fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message) }) router.Run(":8080")}
Json和protobuf渲染
syntax = "proto3";option go_package = ".;proto";message Teacher { string name = 1; repeated string course = 2;}
package mainimport ( "net/http" "github.com/gin-gonic/gin" "OldPackageTest/gin_start/ch06/proto")func main() { router := gin.Default() router.GET("/moreJSON", moreJSON)//直接返回的是json格式数据 router.GET("/someProtoBuf", returnProto)//返回的是proto格式数据(二进制形式) router.Run(":8083")}func returnProto(c *gin.Context) { course := []string{"python", "go", "微服务"} user := &proto.Teacher{ Name: "bobby", Course: course, } c.ProtoBuf(http.StatusOK, user)}func moreJSON(c *gin.Context) { var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "bobby" msg.Message = "这是一个测试json" msg.Number = 20 c.JSON(http.StatusOK, msg)}
表单验证


package mainimport ( "fmt" "net/http" "reflect" "strings" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/locales/en" "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" en_translations "github.com/go-playground/validator/v10/translations/en" zh_translations "github.com/go-playground/validator/v10/translations/zh")var trans ut.Translatortype LoginForm struct { User string `json:"user" binding:"required,min=3,max=10"` Password string `json:"password" binding:"required"`}type SignUpForm struct { Age uint8 `json:"age" binding:"gte=1,lte=130"`大于1小于130 Name string `json:"name" binding:"required,min=3"`最小长度为3 Email string `json:"email" binding:"required,email"`内置检测邮箱格式 Password string `json:"password" binding:"required"` RePassword string `json:"re_password" binding:"required,eqfield=Password"` //跨字段保持一致}func removeTopStruct(fileds map[string]string) map[string]string { rsp := map[string]string{} for field, err := range fileds { rsp[field[strings.Index(field, ".")+1:]] = err } return rsp}//表单验证出错时翻译中文信息func InitTrans(locale string) (err error) { //修改gin框架中的validator引擎属性, 实现定制 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { //注册一个获取json的tag的自定义方法 v.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) zhT := zh.New() //中文翻译器 enT := en.New() //英文翻译器 //第一个参数是备用的语言环境,后面的参数是应该支持的语言环境 uni := ut.New(enT, zhT, enT) trans, ok = uni.GetTranslator(locale) if !ok { return fmt.Errorf("uni.GetTranslator(%s)", locale) } switch locale { case "en": en_translations.RegisterDefaultTranslations(v, trans) case "zh": zh_translations.RegisterDefaultTranslations(v, trans) default: en_translations.RegisterDefaultTranslations(v, trans) } return } return}func main() { //代码侵入性很强 中间件 if err := InitTrans("zh"); err != nil { fmt.Println("初始化翻译器错误") return } router := gin.Default() router.POST("/loginJSON", func(c *gin.Context) { var loginForm LoginForm if err := c.ShouldBind(&loginForm); err != nil { errs, ok := err.(validator.ValidationErrors) if !ok { c.JSON(http.StatusOK, gin.H{ "msg": err.Error(), }) } c.JSON(http.StatusBadRequest, gin.H{ "error": removeTopStruct(errs.Translate(trans)), }) return } c.JSON(http.StatusOK, gin.H{ "msg": "登录成功", }) }) router.POST("/signup", func(c *gin.Context) { var signUpFrom SignUpForm if err := c.ShouldBind(&signUpFrom); err != nil { fmt.Println(err.Error()) c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "msg": "注册成功", }) }) _ = router.Run(":8083")}
gin中间件
#使用r := gin.New()#替代// 默认启动方式,包含 Logger、Recovery 中间件r := gin.Default()
func main() { // 创建一个不包含中间件的路由器 r := gin.New() // 全局中间件 // 使用 Logger 中间件 r.Use(gin.Logger()) // 使用 Recovery 中间件 r.Use(gin.Recovery()) // 路由添加中间件,可以添加任意多个 r.GET("/benchmark", MyBenchLogger(), benchEndpoint) // 路由组中添加中间件 // authorized := r.Group("/", AuthRequired()) // exactly the same as: authorized := r.Group("/") // per group middleware! in this case we use the custom created // AuthRequired() middleware just in the "authorized" group. authorized.Use(AuthRequired()) { authorized.POST("/login", loginEndpoint) authorized.POST("/submit", submitEndpoint) authorized.POST("/read", readEndpoint) // nested group testing := authorized.Group("testing") testing.GET("/analytics", analyticsEndpoint) } // Listen and serve on 0.0.0.0:8080 r.Run(":8080")}
func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // Set example variable c.Set("example", "12345") // before request c.Next() // after request latency := time.Since(t) log.Print(latency) // access the status we are sending status := c.Writer.Status() log.Println(status) }}func main() { r := gin.New() r.Use(Logger()) r.GET("/test", func(c *gin.Context) { example := c.MustGet("example").(string) // it would print: "12345" log.Println(example) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080")}
设置静态文件路径和html文件
package mainimport ( "net/http" "github.com/gin-gonic/gin")func main() { // 创建一个默认的路由引擎 r := gin.Default() // 配置模板 r.LoadHTMLGlob("templates/**/*") //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") // 配置静态文件夹路径 第一个参数是api,第二个是文件夹路径 r.StaticFS("/static", http.Dir("./static")) // GET:请求方式;/hello:请求的路径 // 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数 r.GET("/posts/index", func(c *gin.Context) { // c.JSON:返回JSON格式的数据 c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ "title": "posts/index", }) }) r.GET("gets/login", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/login.tmpl", gin.H{ "title": "gets/login", }) }) // 启动HTTP服务,默认在0.0.0.0:8080启动服务 r.Run()}
<html> <h1> {{ .title }} </h1></html>
{{ define "posts/index.tmpl" }}<html><h1> {{ .title }}</h1><p>Using posts/index.tmpl</p></html>{{ end }}
{{ define "users/index.tmpl" }}<html><h1> {{ .title }}</h1><p>Using users/index.tmpl</p></html>{{ end }}
优雅重启或停止
package mainimport ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin")func main() { router := gin.Default() router.GET("/", func(c *gin.Context) { time.Sleep(5 * time.Second) c.String(http.StatusOK, "Welcome Gin Server") }) srv := &http.Server{ Addr: ":8080", Handler: router, } go func() { // service connections if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. quit := make(chan os.Signal) // kill (no param) default send syscanll.SIGTERM // kill -2 is syscall.SIGINT // kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutdown Server ...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } // catching ctx.Done(). timeout of 5 seconds. select { case <-ctx.Done(): log.Println("timeout of 5 seconds.") } log.Println("Server exiting")}