快速入门
第一个demo
func main() {r := gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"msg": "pong",})})r.Run(":8777")}
使用get、post、put等http方法
func main() {// 使用默认中间件创建一个gin路由器// logger and recovery (crash-free) 中间件router := gin.Default()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: v1v1 := router.Group("/v1"){v1.POST("/login", loginEndpoint)v1.POST("/submit", submitEndpoint)v1.POST("/read", readEndpoint)}// Simple group: v2v2 := router.Group("/v2"){v2.POST("/login", loginEndpoint)v2.POST("/submit", submitEndpoint)v2.POST("/read", readEndpoint)}router.Run(":8777")}
带参数的url
func main() {r := gin.Default()goodsGroup := r.Group("/goods"){goodsGroup.GET("", goodsList)goodsGroup.GET("/:id/:action", goodsDetail)//goodsGroup.GET("/:id/*action", goodsDetail)goodsGroup.POST("", createGoods)}r.Run(":8777")}func goodsList(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"name": "list",})}func goodsDetail(c *gin.Context) {id := c.Param("id")action := c.Param("action")c.JSON(http.StatusOK, gin.H{"id": id,"action": action,})}func createGoods(c *gin.Context) {}
获取路由分组的参数
type Person struct {ID int `uri:"id" binding:"required"`Name string `uri:"name" binding:"required"`}func main() {r := gin.Default()r.GET("/:name/:id", func(c *gin.Context) {var person Personif err := c.ShouldBindUri(&person); err != nil {c.Status(404)return}c.JSON(http.StatusOK, gin.H{"name": person.Name,"id": person.ID,})})r.Run(":8777")}
获取参数
获取get /post参数
func main() {r := gin.Default()r.GET("/welcome", welcome)r.POST("/formPost", formPost)r.Run(":8777")}func welcome(c *gin.Context) {firstname := c.DefaultQuery("first", "lcd")lastname := c.DefaultQuery("last", "qq")c.JSON(http.StatusOK, gin.H{"f": firstname,"l": lastname,})}func formPost(c *gin.Context) {msg := c.PostForm("msg")nick := c.DefaultPostForm("nick", "anonymous")c.JSON(http.StatusOK, gin.H{"msg": msg,"nick": nick,})}
JSON、ProtoBuf 渲染
输出json和protobuf
syntax = "proto3";option go_package = ".;proto";message Teacher {string name = 1;repeated string course = 2;}
func main() {r := gin.Default()// gin.H is a shortcut for map[string]interface{}r.GET("/someJSON", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})})r.GET("/moreJSON", func(c *gin.Context) {// You also can use a structvar msg struct {Name string `json:"user"`Message stringNumber int}msg.Name = "Lena"msg.Message = "hey"msg.Number = 123// Note that msg.Name becomes "user" in the JSON// Will output : {"user": "Lena", "Message": "hey", "Number": 123}c.JSON(http.StatusOK, msg)})r.GET("/someProtoBuf", func(c *gin.Context) {courses := []string{"python", "django", "go"}// The specific definition of protobuf is written in the testdata/protoexample file.data := &proto.Teacher{Name: "lll",Course: courses,}// Note that data becomes binary data in the response// Will output protoexample.Test protobuf serialized datac.ProtoBuf(http.StatusOK, data)})r.Run(":8777")}
pureJSON
通常情况下,JSON会将特殊的HTML字符替换为对应的unicode字符,比如<替换为\u003c,如果想原样输出html,则使用PureJSON
func main() {r := gin.Default()// Serves unicode entitiesr.GET("/json", func(c *gin.Context) {c.JSON(200, gin.H{"html": "<b>Hello, world!</b>",})})// Serves literal charactersr.GET("/purejson", func(c *gin.Context) {c.PureJSON(200, gin.H{"html": "<b>Hello, world!</b>",})})r.Run(":8777")}
表单验证
表单的基本验证(登录注册)
Gin使用 go-playground/validator 验证参数,查看完整文档。测试
package mainimport ("fmt""net/http""reflect""strings""github.com/go-playground/locales/en"ut "github.com/go-playground/universal-translator"en_translations "github.com/go-playground/validator/v10/translations/en"zh_translations "github.com/go-playground/validator/v10/translations/zh""github.com/go-playground/locales/zh""github.com/gin-gonic/gin/binding""github.com/go-playground/validator/v10""github.com/gin-gonic/gin")var trans ut.Translatortype Login struct {User string ` json:"user" binding:"required,min=3" `Password string ` json:"password" binding:"required"`}type SignUp struct {Age uint8 `json:"age" binding:"gte=1,lte=130"`Name string `json:"name" binding:"required"`Email string `json:"email" binding:"required,email"`Password string `json:"password" binding:"required"`RePassword string `json:"re_password" binding:"required,eqfield=Password"`}func RemoveTopStruct(fields map[string]string) map[string]string {rsp := map[string]string{}for field, err := range fields {rsp[field[strings.Index(field, ".")+1:]] = err}return rsp}func InitTrans(locale string) (err error) {if v, ok := binding.Validator.Engine().(*validator.Validate); ok {v.RegisterTagNameFunc(func(field reflect.StructField) string {name := strings.SplitN(field.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}r := gin.Default()r.POST("/loginJSON", func(c *gin.Context) {var login Loginif err := c.ShouldBind(&login); err != nil {fmt.Println(err.Error())c.JSON(http.StatusBadRequest, gin.H{"error": err.Error(),})return}c.JSON(http.StatusOK, gin.H{"msg": "login success",})})r.POST("/signUp", func(c *gin.Context) {var signUp SignUpif err := c.ShouldBind(&signUp); err != nil {errs, ok := err.(validator.ValidationErrors)if !ok {c.JSON(http.StatusOK, gin.H{"msg": err.Error(),})return}c.JSON(http.StatusBadRequest, gin.H{"error": RemoveTopStruct(errs.Translate(trans)),})return}c.JSON(http.StatusOK, gin.H{"msg": "signUp success",})})r.Run(":8777")}
import requests#loginresp = requests.post("http://127.0.0.1:8777/loginJSON", json={"user": "xdd","password": "1233"})print(resp.text)
import requests#signUpresp = requests.post("http://127.0.0.1:8777/signUp", json={"age": 18,"name": "xdd","email": "12@qq.com","password": "aaa","re_password": "aaa",})print(resp.text)
中间件和next函数
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。默认启动
// 默认启动方式,包含 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 grouptesting := authorized.Group("testing")testing.GET("/analytics", analyticsEndpoint)}// Listen and serve on 0.0.0.0:8080r.Run(":8080")}
自定义组件
func main() {r := gin.New()r.Use(Logger())r.GET("/test", func(c *gin.Context) {example := c.MustGet("example").(string)log.Println(example)})r.Run(":8777")}func Logger() gin.HandlerFunc {return func(c *gin.Context) {t := time.Now()c.Set("example", "123")c.Next()end := time.Since(t)log.Println(end)status := c.Writer.Status()log.Println(status)}}
通过c.abort()终止中间件后续逻辑的执行
