简介
Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点
hello world
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
r.GET("/hello", func(c *gin.Context) {
c.String(http.StatusOK, "hello World!")
})
// 3.监听端口,默认在8080
// Run("里面不指定端口号默认为8080")
r.Run(":8000")
}
访问:http://localhost:8000/hello
结果:hello World!
路由
gin 框架中采用的路由库是基于httprouter做的https://github.com/julienschmidt/httprouter
restful 风格的api
gin支持Restful风格的API,即Representational State Transfer的缩写。直接翻译的意思是”表现层状态转化”,是一种互联网应用程序的API设计理念:URL定位资源,用HTTP描述操作
- 获取文章: GET /blog/1
- 添加文章: POST /blog/1
- 修改文件: PUT /blog/1
- 删除文章: DELETE /blog/1
url都是一样的,用于定位资源,HTTP方法描述操作
参数获取
api参数获取
可以通过Context的Param方法来获取API参数
url参数获取
URL参数可以通过DefaultQuery()或Query()方法获取
DefaultQuery()若参数不村则,返回默认值,Query()若不存在,返回空串
func main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
r.GET("/hello/:name/*action", func(c *gin.Context) {
// 获取api中的参数
name := c.Param("name")
action := c.Param("action")
// 获取url中的参数
password := c.Query("password")
c.String(http.StatusOK, "hello %s, your action is %s!, your password:%s", name, action, password)
})
// 3.监听端口,默认在8080
// Run("里面不指定端口号默认为8080")
r.Run(":8000")
}
访问http://localhost:8000/hello/张三/testaction?password=123
结果hello 张三, your action is /testaction!, your password:123
表单参数
表单传输为post请求,http常见的传输格式为四种:
- application/json
- application/x-www-form-urlencoded
- application/xml
- multipart/form-data
表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或from-data格式的参数
username := c.PostForm("username")
password := c.PostForm("userpassword")
获取单个文件
file, err := c.FormFile("file")
获取多个文件
form, err := c.MultipartForm()
files := form.File["files"]
routes group
- routes group是为了管理一些相同的URL
- httproter会将所有路由规则构造一颗前缀树
func main() { // 1.创建路由 // 默认使用了2个中间件Logger(), Recovery() r := gin.Default() // 路由组1 ,处理GET请求 v1 := r.Group("/v1") // {} 是书写规范 { v1.GET("/login", login) v1.GET("submit", submit) } v2 := r.Group("/v2") { v2.POST("/login", login) v2.POST("/submit", submit) } r.Run(":8000") } func login(c *gin.Context) { name := c.DefaultQuery("name", "jack") c.String(200, fmt.Sprintf("hello %s\n", name)) } func submit(c *gin.Context) { name := c.DefaultQuery("name", "lily") c.String(200, fmt.Sprintf("hello %s\n", name)) }
数据解析与绑定
json解析与绑定
// 将request的body中的数据,自动按照json格式解析到结构体
err := c.ShouldBindJSON(&json)
表单解析与绑定
// Bind()默认解析并绑定form格式
// 根据请求头中content-type自动推断
err := c.Bind(&form);
url解析与绑定
// Bind()默认解析并绑定form格式
// 根据请求头中content-type自动推断
err := c.ShouldBindUri(&login)
gin渲染
各种数据格式的响应
- json
c.JSON(http.StatusOK, gin.H{"msg": fmt.Sprintf("恭喜你登录成功,欢迎:%s", user.Name)})
- struct
c.JSON(http.StatusOK, user) // 跟json一样,调用c.JSON方法
- xml
结果c.XML(http.StatusOK, gin.H{"msg": fmt.Sprintf("恭喜你登录成功,欢迎:%s", user.Name)})
<map> <msg>恭喜你登录成功,欢迎:zhangsan</msg> </map>
- yaml
结果c.YAML(http.StatusOK, gin.H{"msg": fmt.Sprintf("恭喜你登录成功,欢迎:%s", user.Name)})
msg: 恭喜你登录成功,欢迎:zhangsan
- protobuf
protobuf格式,谷歌开发的高效存储读取的工具
reps := []int64{int64(1), int64(2)}
// 定义数据
label := "label"
// 传protobuf格式数据
data := &protoexample.Test{
Label: &label,
Reps: reps,
}
c.ProtoBuf(200, data)
结果
HTML模板响应
- gin支持加载HTML模板, 然后根据模板参数进行配置并返回相应的数据,本质上就是字符串替换
// 加载模板文件
r.LoadHTMLGlob("html/*")
// 引入静态文件
r.Static("/assets", "./assets")
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "html/index.html", gin.H{"title": "我是标题", "address": "https://baidu.com"})
})
html/index.html
{{ define "html/index.html" }}
{{template "html/header" .}}
百度{{.address}}
{{template "html/footer" .}}
<img src="assets/1.jpg"/>
{{ end }}
html/header.html
{{define "html/header"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{.title}}</title>
</head>
<body>
{{end}}
html/footer.html
{{define "html/footer"}}
</body>
</html>
{{ end }}
重定向
// 重定向
r.GET("/bd", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
})
中间件
// 定义中间
func TimeCost() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
fmt.Println("中间件开始执行了")
// 设置变量到Context的key中,可以通过Get()取
c.Set("request", "中间件")
time.Sleep(time.Second * 3)
status := c.Writer.Status()
fmt.Println("中间件执行完毕", status)
t2 := time.Since(t)
fmt.Println("time:", t2)
c.Set("time_cost", t2)
}
}
r.Use(middleware.TimeCost())
// 测试中间件
r.GET("/test_middleware", func(c *gin.Context) {
// 取值
req, _ := c.Get("request")
timeCost, _ := c.Get("time_cost")
fmt.Println("request:", req)
// 页面接收
c.JSON(200, gin.H{"request": req, "time_cost": timeCost})
})
系统日志
中间件开始执行了
中间件执行完毕 200
time: 3.000636802s
request: 中间件
返回结果
{
"request": "中间件",
"time_cost": 3000636802
}
会话控制
Cookie
- HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出
- Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思
- Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求
- Cookie由服务器创建,并发送给浏览器,最终由浏览器保存
// 给客户端设置cookie
// maxAge int, 单位为秒
// path,cookie所在目录
// domain string,域名
// secure 是否智能通过https访问
// httpOnly bool 是否允许别人通过js获取自己的cookie
c.SetCookie("key_cookie", "value_cookie", 60, "/",
"localhost", false, true)
缺点
- 不安全,明文
- 增加带宽消耗
- 可以被禁用
- cookie有上限
Session
其实就是一个local store
日志
// Logging to a file.
f, _ := os.Create("gin.log")
gin.DefaultWriter = io.MultiWriter(f)
// 如果需要同时将日志写入文件和控制台,请使用以下代码。
// gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
r := gin.Default()