Gin 简介

Gin 是使用 Go/golang 语言实现的 HTTP Web 框架,接口简洁、性能极高。

Gin 特性

  • 快速:路由不使用反射,基于Radix树,内存占用少。
  • 中间件:HTTP请求,可先经过一系列中间件处理,例如:Logger,Authorization,GZIP等。这个特性和 NodeJs 的 Koa、Express 框架很像。中间件机制也极大地提高了框架的可扩展性。
  • 异常处理:服务始终可用,不会宕机,Gin 可以捕获 panic,并恢复。而且有极为便利的机制处理HTTP请求过程中发生的错误。
  • JSON:Gin可以解析并验证请求的JSON,对Restful API的开发尤其有用。
  • 路由分组:将需要授权和不需要授权的API分组,不同版本的API分组,分组可嵌套,性能不受影响。
  • 渲染内置:原生支持JSON,XML和HTML的渲染。

Go环境安装配置

  • 安装linux go
  • 安装 Go (Mac)
$ brew install go
$ go version
# go version go1.17.7 darwin/amd64
  • 设置环境变量

在环境配置文件~/.bashrc中添加 GOPATH 变量

export GOPATH=~/go
export PATH=$PATH:$GOPATH/bin

添加完后,刷新配置

source ~/.bashrc

在环境配置文件~/.bash_profile中添加 GOPATH 变量

cd ~
vim ~/.bash_profile

添加完后,刷新配置

source ~/.bash_profile

  • 安装一些辅助的工具库

由于网络原因,不能够直接访问 http://golang.org,但相关的库已经镜像到 Golang - Github

例如,直接安装 go-outline 时会报网络错误,因为golang.org/x/toolsgo-outline的依赖库。

go get

$ go get -u -v github.com/ramya-rao-a/go-outline
github.com/ramya-rao-a/go-outline (download)
Fetching https://golang.org/x/tools/go/buildutil?go-get=1
https fetch failed: Get https://golang.org/x/tools/go/buildutil?go-get=1:
dial tcp 216.239.37.1:443: i/o timeout

go install

go install github.com/ramya-rao-a/go-outline@latest

因此,可以先从 Github 手动安装好,再安装 go-outline 和 goreturns

git clone https://github.com/golang/tools.git $GOPATH/src/golang.org/x/tools
go get -v github.com/ramya-rao-a/go-outline
go get -v github.com/sqs/goreturns
go get -v github.com/rogpeppe/godef

Go语言有大量的辅助工具,如果你使用VSCode,将会提示你将必要的工具,例如:静态检查、自动补全等工具依次安装完毕。

  • 安装 Gin
go get -u -v github.com/gin-gonic/gin

-v:打印出被构建的代码包的名字
-u:已存在相关的代码包,强行更新代码包及其依赖包

第一个Gin程序

在一个空文件夹里新建文件main.go

// geektutu.com
// main.go
package mainimport "github.com/gin-gonic/gin"func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {c.String(200, "Hello, Geektutu")})r.Run() // listen and serve on 0.0.0.0:8080
}
  1. 首先,使用了gin.Default()生成了一个实例r,这个实例即 WSGI 应用程序。
  2. 接下来,使用r.Get("/", ...)声明了一个路由,告诉 Gin 什么样的URL 能触发传入的函数,这个函数返回我们想要显示在用户浏览器中的信息。
  3. 最后用 r.Run()函数来让应用运行在本地服务器上,默认监听端口是 8080,可以传入参数设置端口,例如r.Run(":9999")即运行在 9999端口。
  • 运行
$ go run main.go
[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
  • 浏览器访问 http://localhost:8080

路由(Route)

路由方法有 GET, POST, PUT, PATCH, DELETE 和 OPTIONS,还有Any,可匹配以上任意类型的请求。

无参数

// 无参数
r.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Who are you?")
})$ curl http://localhost:9999/
Who are you?

curl参数可参考https://man.linuxde.net/curl

解析路径参数

有时候我们需要动态的路由

例如:

/user/:name,通过调用不同的 url 来传入不同的 name。

/user/:name/*role

* 代表可选

// 匹配 /user/geektutu
r.GET("/user/:name", func(c *gin.Context) {name := c.Param("name")c.String(http.StatusOK, "Hello %s", name)
})$ curl http://localhost:9999/user/geektutu
Hello geektutu

获取Query参数

// 匹配users?name=xxx&role=xxx,role可选
r.GET("/users", func(c *gin.Context) {name := c.Query("name")role := c.DefaultQuery("role", "teacher") // query 参数默认值c.String(http.StatusOK, "%s is a %s", name, role)
})$ curl "http://localhost:9999/users?name=Tom&role=student"
Tom is a student

获取POST参数

// POST
r.POST("/form", func(c *gin.Context) {username := c.PostForm("username")password := c.DefaultPostForm("password", "000000") // 可设置默认值// 返回json格式c.JSON(http.StatusOK, gin.H{"username": username,"password": password,})
})$ curl http://localhost:9999/form  -X POST -d 'username=geektutu&password=1234'
{"password":"1234","username":"geektutu"}

form-data??

Query和POST混合参数

// GET 和 POST 混合
r.POST("/posts", func(c *gin.Context) {id := c.Query("id")page := c.DefaultQuery("page", "0")username := c.PostForm("username")password := c.DefaultPostForm("username", "000000") // 可设置默认值c.JSON(http.StatusOK, gin.H{"id":       id,"page":     page,"username": username,"password": password,})
})$ curl "http://localhost:9999/posts?id=9876&page=7"  -X POST -d 'username=geektutu&password=1234'
{"id":"9876","page":"7","password":"1234","username":"geektutu"}

Map参数(字典参数)

r.POST("/post", func(c *gin.Context) {ids := c.QueryMap("ids")names := c.PostFormMap("names")c.JSON(http.StatusOK, gin.H{"ids":   ids,"names": names,})
})$ curl -g "http://localhost:9999/post?ids[Jack]=001&ids[Tom]=002" -X POST -d 'names[a]=Sam&names[b]=David'
{"ids":{"Jack":"001","Tom":"002"},"names":{"a":"Sam","b":"David"}}

重定向(Redirect)

r.GET("/redirect", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "/index")
})r.GET("/goindex", func(c *gin.Context) {c.Request.URL.Path = "/"r.HandleContext(c)
})
$ curl -i http://localhost:9999/redirect
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=utf-8
Location: /
Date: Thu, 08 Aug 2019 17:22:14 GMT
Content-Length: 36<a href="/">Moved Permanently</a>.$ curl "http://localhost:9999/goindex"
Who are you?

分组路由(Grouping Routes)

如果有一组路由,前缀都是/api/v1开头,是否每个路由都需要加上/api/v1这个前缀呢?

答案:不需要

分组路由可以解决这个问题。

利用分组路由还可以更好地实现权限控制,例如将需要登录鉴权的路由放到同一分组中去,简化权限控制。

// group routes 分组路由
defaultHandler := func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"path": c.FullPath(),})
}
// group: v1
v1 := r.Group("/v1")
{v1.GET("/posts", defaultHandler)v1.GET("/series", defaultHandler)
}
// group: v2
v2 := r.Group("/v2")
{v2.GET("/posts", defaultHandler)v2.GET("/series", defaultHandler)
}$ curl http://localhost:9999/v1/posts
{"path":"/v1/posts"}
$ curl http://localhost:9999/v2/posts
{"path":"/v2/posts"}

上传文件

单个文件

r.POST("/upload1", func(c *gin.Context) {file, _ := c.FormFile("file")// c.SaveUploadedFile(file, dst)c.String(http.StatusOK, "%s uploaded!", file.Filename)
})

多个文件

r.POST("/upload2", func(c *gin.Context) {// Multipart formform, _ := c.MultipartForm()files := form.File["upload[]"]for _, file := range files {log.Println(file.Filename)// c.SaveUploadedFile(file, dst)}c.String(http.StatusOK, "%d files uploaded!", len(files))
})

HTML模板(Template)

type student struct {Name stringAge  int8
}r.LoadHTMLGlob("templates/*")stu1 := &student{Name: "Geektutu", Age: 20}
stu2 := &student{Name: "Jack", Age: 22}
r.GET("/arr", func(c *gin.Context) {c.HTML(http.StatusOK, "arr.tmpl", gin.H{"title":  "Gin","stuArr": [2]*student{stu1, stu2},})
})
<!-- templates/arr.tmpl -->
<html>
<body><p>hello, {{.title}}</p>{{range $index, $ele := .stuArr }}<p>{{ $index }}: {{ $ele.Name }} is {{ $ele.Age }} years old</p>{{ end }}
</body>
</html>$ curl http://localhost:9999/arr<html>
<body><p>hello, Gin</p><p>0: Geektutu is 20 years old</p><p>1: Jack is 22 years old</p>
</body>
</html>
  • Gin默认使用模板Go语言标准库的模板text/templatehtml/template,语法与标准库一致,支持各种复杂场景的渲染。
  • 参考官方文档text/template,html/template

中间件(Middleware)

// 作用于全局
r.Use(gin.Logger())
r.Use(gin.Recovery())// 作用于单个路由
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)// 作用于某个组
authorized := r.Group("/")
authorized.Use(AuthRequired())
{authorized.POST("/login", loginEndpoint)authorized.POST("/submit", submitEndpoint)
}

如何自定义中间件呢?

func Logger() gin.HandlerFunc {return func(c *gin.Context) {t := time.Now()// 给Context实例设置一个值c.Set("geektutu", "1111")// 请求前c.Next()// 请求后latency := time.Since(t)log.Print(latency)}
}

热加载调试 Hot Reload

Python 的 Flask框架,有 debug 模式,启动时传入 debug=True 就可以热加载(Hot Reload, Live Reload)了。即更改源码,保存后,自动触发更新,浏览器上刷新即可。免去了杀进程、重新启动之苦。

Gin 原生不支持,但有很多额外的库可以支持。例如

  • http://github.com/codegangsta/gin
  • http://github.com/pilu/fresh

这次,我们采用 http://github.com/pilu/fresh 。

go get -v -u github.com/pilu/fresh

安装好后,只需要将go run main.go命令换成fresh即可。

每次更改源文件,代码将自动重新编译(Auto Compile)。

允许跨域配置

todo

请求数据格式

form-data

todo

mulitipart

todo

x-www-form-urlencoded

todo

json

todo

参考:github.com/pilu/fresh - Github

相关链接

  • Golang Gin - Github
  • Gin Web Framework - 英文官方网站

Go Gin 入门教程相关推荐

  1. Kafka入门教程与详解

    1 Kafka入门教程 1.1 消息队列(Message Queue) Message Queue消息传送系统提供传送服务.消息传送依赖于大量支持组件,这些组件负责处理连接服务.消息的路由和传送.持久 ...

  2. 【CV】Pytorch一小时入门教程-代码详解

    目录 一.关键部分代码分解 1.定义网络 2.损失函数(代价函数) 3.更新权值 二.训练完整的分类器 1.数据处理 2. 训练模型(代码详解) CPU训练 GPU训练 CPU版本与GPU版本代码区别 ...

  3. python tornado教程_Tornado 简单入门教程(零)——准备工作

    前言: 这两天在学着用Python + Tornado +MongoDB来做Web开发(哈哈哈这个词好高端).学的过程中查阅了无数资料,也收获了一些经验,所以希望总结出一份简易入门教程供初学者参考.完 ...

  4. python向量计算库教程_NumPy库入门教程:基础知识总结

    原标题:NumPy库入门教程:基础知识总结 视学算法 | 作者 知乎专栏 | 来源 numpy可以说是 Python运用于人工智能和科学计算的一个重要基础,近段时间恰好学习了numpy,pandas, ...

  5. mysql query browswer_MySQL数据库新特性之存储过程入门教程

    MySQL数据库新特性之存储过程入门教程 在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力.在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用 ...

  6. python tensorflow教程_TensorFlow入门教程TensorFlow 基本使用T

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 TensorFlow入门教程 TensorFlow 基本使用 TensorFlow官方中文教程 TensorFlow 的特点: 使用图 (graph) 来 ...

  7. air调用java,AIR2.0入门教程:与Java应用交互

    在之前的一篇文章中,我介绍了如何使用AIR2.0新增的NativeProcess类与本地进程进行交互和通讯,在那个例子里面我们使用了C++ 的代码,实际上只要是基于命令行的标准输入输出,AIR2.0的 ...

  8. 【Arduino】开发入门教程【一】什么是Arduino

    Arduino Arduino 是一款便捷灵活.方便上手的开源电子原型平台,包含硬件(各种型号的arduino板)和软件(arduino IDE).它适用于艺术家.设计师.爱好者和对于"互动 ...

  9. python 三分钟入门_Cython 三分钟入门教程

    作者:perrygeo 译者:赖勇浩(http://laiyonghao.com) 原文:http://www.perrygeo.net/wordpress/?p=116 我最喜欢的是Python,它 ...

最新文章

  1. 50、mysql基于mysql-proxy读写分离实战
  2. The build tools for v141 (Platform Toolset = 'v141') cannot be found
  3. 十个鲜为人知的Linux命令 - Part 5
  4. Flink从入门到精通100篇(三)-如何利用InfluxDB+Grafana搭建Flink on YARN作业监控大屏环境
  5. xunsearch php,GitHub - ziyueit/xunsearch: 迅搜的一个PHP封装类
  6. 第5章 初识JQuery
  7. .net10个必备工具
  8. “约见”面试官系列之常见面试题第九篇vue实现双向绑定原理(建议收藏)
  9. java 数据结构 pdf_数据结构java版本.pdf
  10. 2020定额水平测算——“15定额工程”一键转换“20定额工程”
  11. win10没有声音(扬声器一直显示未插入)
  12. 国外计算机课程lab,计算机系统实验之bomblab
  13. 产量预测文献读后整理
  14. 贷款市场报价利率(LPR)与贷款基准利率介绍
  15. JS字符串过滤数字_过滤大写数字
  16. 地震学类毕业论文文献都有哪些?
  17. Java 对类的重命名
  18. English Learning - L2-15 英音地道语音语调 语音语调四步法 2023.04.17 周一
  19. 谷歌第一个开源编程语言_我的第一个开源冒险
  20. 如何用OpenGL的点精灵(point sprite)绘制雪花?

热门文章

  1. Linux期末复习题
  2. paloalto防火墙注册
  3. Python自动化开发学习的第十一周----WEB框架--Django基础
  4. 2022.02.05 Mysterious Present神秘的礼物
  5. 《Programming in Scala》读书笔记(持续更新) - passover的个人空间 - DOIT博客 - 多易网...
  6. Java List转Array
  7. 【排列问题】-四阶数独
  8. nrm : 无法加载文件 C:\Users\HUAWEI\AppData\Roaming\npm\nrm.ps1,因为在此系统上禁止运行脚本
  9. 全日制和非全日制;定向和非定向区别联系
  10. ps教程,教你做最简单最美丽的相片