疾速入门
- 装置并配置GO工作区
- 在GOPATH的src目录下新建我的项目文件夹
- 应用
go mod init
命令初始化我的项目 - 应用
go get -u github.com/gin-gonic/gin
命令装置gin - 示例代码:
package mainimport "github.com/gin-gonic/gin"func main() { // 创立默认路由 r := gin.Default() // 绑定路由规定和执行函数,当拜访/ping接口时就会执行前面的函数 r.GET("/ping", func(c *gin.Context) { // 该函数间接返回JSON字符串 c.JSON(200, gin.H{ "message": "pong", }) }) // 启动并监听端口,默认8080,可应用:r.Run(":8000")批改监听端口 r.Run()}
- 浏览器或postman拜访:
localhost:8080/ping
,即可胜利返回json字符串
路由
API参数
在门路中应用/:paramName
或者/*paramName
作为占位符,可在代码中通过*gin.Context
的param
办法获取到API参数,应用冒号占位符获取到的API参数不蕴含门路中的/
,应用星号占位符则蕴含/
func main() { // 创立路由 r := gin.Default() r.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") c.JSON(http.StatusOK, gin.H{ "name":name, "action":action, }) }) // 默认端口号是8080 r.Run(":8000")}
应用postman申请http://127.0.0.1:8000/user/lee/index.html
,返回的json格局如下:
{ "action": "/index.html", "name": "lee"}
URL参数
应用DefaultQuery或者Query办法能够获取前端传递的URL参数
DefaultQuery:可指定默认值
Query:不可指定默认值
func main() { // 创立路由 r := gin.Default() r.GET("/add_user", func(c *gin.Context) { name := c.Query("name") age := c.DefaultQuery("age", "23") c.JSON(http.StatusOK, gin.H{ "name":name, "age":age, }) }) // 默认端口号是8080 r.Run(":8000")}
postman拜访:http://127.0.0.1:8000/add_user?name=lee&age=18
,返回如下:
{ "age": "18", "name": "lee"}
postma拜访:http://127.0.0.1:8000/add_user?name=lee
,返回如下:
{ "age": "23", "name": "lee"}
表单参数
表单传输为post申请,http常见的传输格局为四种:
- application/json
- application/x-www-form-urlencoded
- application/xml
- multipart/form-data
表单参数能够通过PostForm()办法获取,该办法默认解析的是x-www-form-urlencoded或from-data格局的参数,还能够应用DefaultPostForm办法指定默认值获取。
func main() { // 创立路由 r := gin.Default() r.POST("/form_post", func(c *gin.Context) { message := c.DefaultPostForm("message", "default message") name := c.PostForm("name") c.JSON(http.StatusOK, gin.H{ "message":message, "name":name, }) }) // 默认端口号是8080 r.Run(":8000")}
应用postman发送申请如下所示:
上传单个文件
func main() { // 创立路由 r := gin.Default() r.POST("/upload", func(c *gin.Context) { file, err := c.FormFile("file") if err != nil { fmt.Println(err) } c.SaveUploadedFile(file, file.Filename) c.JSON(http.StatusOK, gin.H{ "message":"ok", "fileName":file.Filename, }) }) // 默认端口号是8080 r.Run(":8000")}
应用postman发送申请如下:
上传特定文件
func main() { // 创立路由 r := gin.Default() r.POST("/upload", func(c *gin.Context) { _, file, err := c.Request.FormFile("file") if err != nil { fmt.Println(err) } if file.Size >= 1024 * 1024 * 2 { c.JSON(http.StatusOK, gin.H{ "message":"文件大小不能超过2M", }) return } if file.Header.Get("Content-Type") != "image/png" { c.JSON(http.StatusOK, gin.H{ "message":"只能上传png格式文件", }) return } c.SaveUploadedFile(file, file.Filename) c.JSON(http.StatusOK, gin.H{ "message":"ok", "fileName":file.Filename, }) }) // 默认端口号是8080 r.Run(":8000")}
应用postman发送申请如下:
上传多个文件
func main() { // 创立路由 r := gin.Default() r.POST("/upload", func(c *gin.Context) { form, err := c.MultipartForm() if err != nil { fmt.Println(err) return } files := form.File["files"] for _, file := range files { err := c.SaveUploadedFile(file, file.Filename) if err != nil { c.JSON(http.StatusOK, gin.H{ "message":"文件上传失败", "err":err, }) return } } c.JSON(http.StatusOK, gin.H{ "message":"文件上传胜利", "upload file count":len(files), }) }) // 默认端口号是8080 r.Run(":8000")}
应用postman调用接口如下:
路由组
路由组(RouterGroup),用于治理一组路由,在不同路由组中的路由可重名
func main() { // 创立路由 r := gin.Default() v1 := r.Group("/v1") v1.GET("/hello", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message":"/v1/hello", }) }) v2 := r.Group("/v2") v2.GET("/hello", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message":"/v2/hello", }) }) // 默认端口号是8080 r.Run(":8000")}
postman别离拜访http://127.0.0.1:8000/v1/hello
和http://127.0.0.1:8000/v2/hello
,返回不同的音讯
自定义404
定义NoRoute之后,如果拜访的地址不在曾经存在的路由中,就会默认执行这个配置的办法,可用于配置404返回信息
func main() { // 创立路由 r := gin.Default() r.NoRoute(func(c *gin.Context) { c.JSON(http.StatusNotFound, gin.H{ "message":"页面丢了!", }) }) // 默认端口号是8080 r.Run(":8000")}
应用postman调用后果如下:
数据绑定
JSON
将前端发送的json数据绑定到构造体上,在构造体中除了定义构造体的参数之外,在参数前面须要定义json的参数名,示意将json中的哪个参数与构造体中的参数进行绑定,binding:"required"
示意该字段为必传,如果为空则报错
func main() { // 创立路由 r := gin.Default() r.GET("/loginJSON", func(c *gin.Context) { var login LoginForm err := c.ShouldBindJSON(&login) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 判断用户名明码是否正确 if login.User != "root" || login.Password != "admin" { c.JSON(http.StatusBadRequest, gin.H{ "status": "304", "message":"登录失败", }) return } c.JSON(http.StatusOK, gin.H{ "status": "200", "message":"登录胜利", }) }) // 默认端口号是8080 r.Run(":8000")}type LoginForm struct { // 表明该属性与传递的json的user属性进行绑定 User string `json:"user" binding:"required"` Password string `json:"password" binding:"required"`}
应用postman调用接口后果如下:
表单
func main() { // 创立路由 r := gin.Default() r.POST("/loginForm", func(c *gin.Context) { // 申明接管的变量 var form LoginForm // Bind()默认解析并绑定form格局 // 依据申请头中content-type主动推断 if err := c.Bind(&form); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if form.User != "root" || form.Password != "admin" { c.JSON(http.StatusBadRequest, gin.H{ "status": "304", "message":"登录失败", }) return } c.JSON(http.StatusOK, gin.H{ "status": "200", "message":"登录胜利", }) }) // 默认端口号是8080 r.Run(":8000")}type LoginForm struct { User string `form:"user" json:"user" binding:"required"` Password string `form:"password" json:"password" binding:"required"`}
应用postman调用接口后果如下:
URI
func main() { // 创立路由 r := gin.Default() r.GET("/login/:user/:password", func(c *gin.Context) { // 申明接管的变量 var login LoginForm // Bind()默认解析并绑定form格局 // 依据申请头中content-type主动推断 if err := c.ShouldBindUri(&login); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if login.User != "root" || login.Password != "admin" { c.JSON(http.StatusBadRequest, gin.H{ "status": "304", "message":"登录失败", }) return } c.JSON(http.StatusOK, gin.H{ "status": "200", "message":"登录胜利", }) }) // 默认端口号是8080 r.Run(":8000")}type LoginForm struct { User string `form:"user" json:"user" uri:"user" binding:"required"` Password string `form:"password" json:"password" uri:"password" binding:"required"`}
应用postman调用后果如下:
数据响应
JSON、Struct、XML、YAML
func main() { // 创立路由 r := gin.Default() // JSON响应 r.GET("/someJSON", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message":"JSON OK", }) }) // 构造体响应 r.GET("/someStruct", func(c *gin.Context) { type Msg struct { Message string } msg := Msg{ Message: "Struct OK", } c.JSON(http.StatusOK, msg) }) // XML响应 r.GET("/someXML", func(c *gin.Context) { c.XML(http.StatusOK, gin.H{ "message":"XML OK", }) }) // YAML响应 r.GET("/someYAML", func(c *gin.Context) { c.YAML(http.StatusOK, gin.H{ "message":"YAML OK", }) }) // 默认端口号是8080 r.Run(":8000")}
不同响应形式返回示例:
// JSON返回{ "message": "JSON OK"}
// Struct返回{ "Message": "Struct OK"}
<!-- XML返回 --><map> <message>XML OK</message></map>
# YAML返回message: YAML OK
重定向
func main() { // 创立路由 r := gin.Default() r.GET("/redirect", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com") }) // 默认端口号是8080 r.Run(":8000")}
重定向之后当应用浏览器拜访http://127.0.0.1:8000/redirect
链接则会主动跳转到百度首页
同步异步
func main() { // 创立路由 r := gin.Default() r.GET("/async", func(c *gin.Context) { copyContext := c.Copy() go func() { time.Sleep(time.Second * 3) log.Println("异步执行:" + copyContext.Request.URL.Path) }() c.JSON(http.StatusOK, gin.H{ "message":"OK", }) }) r.GET("/sync", func(c *gin.Context) { time.Sleep(3 * time.Second) log.Println("同步执行:" + c.Request.URL.Path) c.JSON(http.StatusOK, gin.H{ "message":"OK", }) }) // 默认端口号是8080 r.Run(":8000")}
在异步中,拜访接口,会间接返回message:OK
响应,而后后盾在3秒之后打印异步执行提醒音讯
在同步中,拜访接口,须要期待3秒之后才会打印并响应
中间件
全局中间件
定义全局中间件之后,所有的申请都会通过该中间件
func main() { // 创立路由 r := gin.Default() // 注册中间件 r.Use(MiddleWare()) // 大括号只是为了代码标准,没有大括号也不会有问题 { r.GET("/middle", func(c *gin.Context) { fmt.Println("接口执行了..") value, _ := c.Get("middleParam") c.JSON(http.StatusOK, gin.H{ "middleParam":value, }) }) } // 默认端口号是8080 r.Run(":8000")}// 定义中间件func MiddleWare() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() fmt.Println("中间件执行了..") // 将变量到Context中,能够通过Get(key)取 c.Set("middleParam", "middle") // 执行函数 c.Next() // 中间件执行完后续操作 duration := time.Since(start) fmt.Println("执行中间件耗时:", duration) }}
在代码中定义了一个中间件,并在中间件中放入了middleParam参数,而后在接口中能够将该参数取出,并且中间件总是会在接口执行之前执行。
应用postman调用接口如下:
日志输入如下:
部分中间件
部分中间件仅在以后接口有用。
func main() { // 创立路由 r := gin.Default() r.GET("/middle_local", MiddleWare(), func(c *gin.Context) { value, _ := c.Get("middleParam") c.JSON(http.StatusOK, gin.H{ "middleParam":value, }) }) // 默认端口号是8080 r.Run(":8000")}
Cookie
Cookie介绍
- HTTP是无状态协定,服务器不能记录浏览器的拜访状态,也就是说服务器不能辨别两次申请是否由同一个客户端收回,Cookie就是解决HTTP协定无状态的计划之一
- Cookie实际上就是服务器保留在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送申请时都会同时将该信息发送给服务器,服务器收到申请后,就能够依据该信息处理申请。
- Cookie由服务器创立,并发送给浏览器,最终由浏览器保留。
Cookie应用
func main() { // 创立路由 r := gin.Default() r.GET("/cookie", func(c *gin.Context) { // 获取客户端是否携带cookie cookie, err := c.Cookie("cookie_key") if err != nil { cookie = "NotSet" // 给客户端设置cookie // maxAge:有效期,单位为秒 // path:cookie所在目录 // domain:域名 // secure:是否只能通过https拜访 // httpOnly:是否容许他人通过js获取本人的cookie c.SetCookie("cookie_key", "cookie_value", 60, "/", "localhost", false, true) } fmt.Printf("cookie的值是: %s\n", cookie) }) // 默认端口号是8080 r.Run(":8000")}
参数校验
Struct构造体校验
type Person struct { // name必填 Name string `form:"name" binding:"required"` // age必填并且大于10 Age int `form:"age" binding:"required,gt=10"` // birthday格式化"2006-01-02" Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`}func main() { // 创立路由 r := gin.Default() r.GET("/struct_verify", func(c *gin.Context) { var person Person err := c.ShouldBind(&person) if err != nil { fmt.Println("Error:", err) c.String(http.StatusBadRequest, fmt.Sprint(err)) return } c.String(http.StatusOK, fmt.Sprint(person)) }) // 3.监听端口,默认在8080 // Run("外面不指定端口号默认为8080") r.Run(":8000")}
当name不传,age小于10时返回后果如下:
Key: 'Person.Name' Error:Field validation for 'Name' failed on the 'required' tagKey: 'Person.Age' Error:Field validation for 'Age' failed on the 'gt' tag
日志
func main() { // 禁用色彩显示 gin.DisableConsoleColor() // 新建日志文件 f, _ := os.Create("gin.log") // 将日志写入到文件中 //gin.DefaultWriter = io.MultiWriter(f) // 同时将日志写入文件和控制台 gin.DefaultWriter = io.MultiWriter(f, os.Stdout) // Run("外面不指定端口号默认为8080") r.Run(":8000")}
本文参加了思否技术征文,欢送正在浏览的你也退出。