首先咱们使用 go moudle来管理依赖, go版本要求在 1.11.1 及以上git
export GO111MODULE=on export GOPROXY=https://mirrors.aliyun.com/goproxy/ 复制代码
初始化 mod 配置github
go mod init
>在当前目录下会生成 go.mod 文件, 做为依赖配置.
复制代码
build项目后会自动下载依赖json
其中在实际项目中发现 goland 没法识别项目代码, 须要 在 goland 的 setting 里设置启用 Go Modulesapi
goland Preference -> Go -> Go Modules(vgo)
-> Enable Go Modules(vgo)intergration
复制代码
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // get 方式请求 r.GET("/get", func(c *gin.Context) { c.JSON(200, "get") }) // post 方式请求 r.POST("/post", func(c *gin.Context) { c.JSON(200, "post") }) // 任意类型请求 r.Any("any", func(c *gin.Context) { c.JSON(200, "any") }) // handle 指定方式请求 r.Handle("POST", "/handle_post", func(c *gin.Context) { c.JSON(200, "handle post") }) //r.Run(":8888") 监听 8888 端口 r.Run() } 复制代码
这里咱们定义了经常使用的 get post方法, 经过 debug 能够看到 any 方式为咱们建立了全部的能够实用的请求的方式, 最后使用了 handle 方式指定方法参数. gin.Default 配置默认的参数, Run 启动 http 服务, 默认监听 8080 端口bash
curl -XPOST http://127.0.0.1:8080/post output: "post" curl -XPOST http://127.0.0.1:8080/handle_post output: "handle post" 复制代码
gin 的路由同请求方式下不能重复定义, 不然启动将会异常退出markdown
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { r := gin.Default() // get 方式请求 r.GET("/getUser/:uid", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "uid": c.Param("uid"), }) }) r.Run() } 复制代码
output:app
curl http://127.0.0.1:8080/getUser/1451 output: {"uid":"1451"} 复制代码
http.StatusOK 引用的 net/http 包中的状态码定义, c.Param() 获取 uid 的值curl
在工做中咱们但愿路由匹配到某个前缀oop
r.GET("/user/*a", func(c *gin.Context) { c.String(http.StatusOK, "hello user") }) 复制代码
这样只要请求到 user 就能够拦截到了, 注意在 gin 里是不容许再设置相似 /user/admin 这样的路由了. 这里是没有路由优先级的.post
请求参数默认值
r.GET("/user", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "name": c.Query("name"), "sex": c.DefaultQuery("sex", "女"), }) }) 复制代码
请求示例
curl http://127.0.0.1:8080/user?name=1 output: {"name":"1","sex":"女"} 复制代码
获取post方式请求的参数
c.String(http.StatusOK, c.PostForm("name")) //获取name值, 默认值为小明 c.String(http.StatusOK, c.DefaultPostForm("name", "小明") 复制代码
r.POST("/user", func(c *gin.Context) { bodyBytes, error := ioutil.ReadAll(c.Request.Body) if error != nil { c.String(http.StatusOK, error.Error()) c.Abort() } c.String(http.StatusOK, string(bodyBytes)) }) 复制代码
curl -XPOST http://127.0.0.1:8080/user?name=1 -d {"name":1} output: {name:1} 复制代码
可是经过 readAll 读取后再获取值是获取不到的. 解决方案就是再将值写回去.
package main import ( "github.com/gin-gonic/gin" "net/http" ) type requestUser struct { Name string `form:"name"` Uid int `form:"uid"` Age int `form:"age"` Date time.Time `form:"date"` } func main() { r := gin.Default() r.POST("/user", userAction) r.Run() } func userAction(c *gin.Context) { var requestUser requestUser //这里是根据请求的content-type进行解析(能够解析json) if err := c.ShouldBind(&requestUser); err != nil { c.String(http.StatusOK, err.Error()) c.Abort() } c.String(http.StatusOK, "%v", requestUser) } 复制代码
curl -XPOST http://127.0.0.1:8080/user -d 'name=xiaoming&age=23' output: {xiaoming 0 23} curl -XPOST http://127.0.0.1:8080/user -d 'name=xiaoming&date=2019-01-01' output: parsing time "2019-01-01" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "T"{xiaoming 0 0 0001-01-01 00:00:00 +0000 UTC} 复制代码
注意咱们在传递时间格式的时候解析发生错误.
这里咱们须要定义时间格式结构体解决
type requestUser struct { Name string `form:"name"` Uid int `form:"uid"` Age int `form:"age"` Date time.Time `form:"date" time_format:"2006-01-02"` } 复制代码
type requestUser struct { Name string `form:"name" binding:"required,len=10"` Uid int `form:"uid"` Age int `form:"age" binding:"required,gt=10"` } 复制代码
curl -H "Content-Type:application/json" -XPOST http://127.0.0.1:8080/user -d '{"name":"xiaoming234342342342342","age":11}' output: Key: 'requestUser.Name' Error:Field validation for 'Name' failed on the 'len' tag{xiaoming234342342342342 0 11} 复制代码
更多验证规则: godoc.org/gopkg.in/go…
###自定义 validator
type requestUser struct { Name string `form:"name" binding:"required,len=10"` Uid int `form:"uid" binding:"checkUidAvailable"` Age int `form:"age" binding:"required,gt=10"` } 复制代码
编写 checkUidAvailable
// Structure func checkUidAvailable(field validator.FieldLevel) bool { if fieldValue, ok := field.Field().Interface().(int); ok { //随机几率 if rand.Intn(2) == fieldValue { return true } } return false } 复制代码
在 main方法中绑定
func main() { r := gin.Default() r.POST("/user", userAction) //绑定 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterValidation("checkUidAvailable", checkUidAvailable) } r.Run() } 复制代码
方法执行, ShouldBind 自动验证
func userAction(c *gin.Context) { var requestUser requestUser if err := c.ShouldBind(&requestUser); err != nil { c.String(http.StatusInternalServerError, err.Error()) c.Abort() return } c.String(http.StatusOK, "%v", requestUser) } 复制代码
f, _ := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f) gin.DefaultErrorWriter = io.MultiWriter(f) r := gin.New() r.Use(gin.Logger(), gin.Recovery()) 复制代码
上面咱们使用了 gin.New 实例的方式声明, r.Use使用了两个中间件, 一个为日志, 另外一个为碰见 panic 抛出异常最上层, 让程序正常运行.
f, _ := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f) gin.DefaultErrorWriter = io.MultiWriter(f) r := gin.Default() 复制代码
默认日志是输出到控制台, 将日志和错误日志所有输出到 gin.log
func ipAuthMiddleWare() gin.HandlerFunc { return func(c *gin.Context) { ipList := []string{ "127.0.0.1", } flag := false clientIp := c.ClientIP() for _, host := range ipList { if clientIp != host { flag = true break } } if !flag { c.String(http.StatusOK, "error") c.Abort() } } } --- r.Use(gin.Logger(), gin.Recovery(), ipAuthMiddleWare()) 复制代码
api := r.Group("/api") { api.GET("user", userAction) } 复制代码
访问 127.0.0.1:8080/api/user 路由组中引入中间件
api := r.Group("/api").Use(ipAuthMiddleWare()) { api.GET("user", userAction) } 复制代码
一样使用 use 便可
json处理: colobu.com/2017/06/21/…