疾速入门
- 装置并配置 GO 工作区
- 在 GOPATH 的 src 目录下新建我的项目文件夹
- 应用
go mod init
命令初始化我的项目 - 应用
go get -u github.com/gin-gonic/gin
命令装置 gin - 示例代码:
package main
import "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' tag
Key: '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")
}
本文参加了思否技术征文,欢送正在浏览的你也退出。