这是我参与「第五届青训营」笔记创作活动的第8天
高性能 web 框架 - Gin
前言:
Golang 的 web 框架选择非常多,从 Java 切换到 Go 的我着实被 Go 的众多 web 框架惊艳到了,直接搜索 Go Web 框架关键字就能搜出五六款不同的框架,属实是激发了我的选择困难症😂
目前流行的 Web 框架有 Gin、Echo、Beego、Iris,各自特点如下:
框架 | 优点 | 缺点 |
---|---|---|
Gin | 速度快、中间件友好 | 框架比较精简,模块较少 |
Echo | 轻量级,路由性能高 | 调试不方便 |
Beego | 功能全面,社区良好 | 比较臃肿 |
Iris | 完备的MVC支持,社区活跃度高 | 不够稳定 |
本次青训营课程主要介绍了 Gin 与字节跳动官方出品的 Herzt 框架,今天先来对 Gin 框架做一个快速上手 ...
Gin 简介
Gin 是用 Golang 编写的 Web 框架,以更好的性能你实现类似 Martini 框架的 API,号称速度比 Martini 快了 40 倍。Gin 封装比较优雅,API 友好,源码注释明确,具有快速灵活、容错方便等特点。
借助框架开发,不仅可以省去很多常用的封装带来的麻烦,也有助于团队的编码风格形成规范。
🎈Gin 中文站点:Gin Web Framework (gin-gonic.com)
第一个 Gin 程序
先从官网的快速入门文档入手,使用 GoLand 创建第一个 Gin 程序 - Hello World。
- 首先创建 Go 项目,添加
main.go
入口文件,然后在终端中使用下面的指令获取 Gin 依赖:$ go get -u github.com/gin-gonic/gin
-
将 Gin 引入到代码中:
import "github.com/gin-gonic/gin"
-
编辑 main.go 代码:
package main import "github.com/gin-gonic/gin" func main() { server := gin.Default() // 创建服务 /* 处理请求 */ server.GET("/hello", func(context *gin.Context) { context.JSONP(200, gin.H{"msg": "Hello World !"}) }) server.Run() // 监听并在 0.0.0.0:8080 上启动服务 }
-
GoLand 中右键运行程序,或者使用如下指令运行:
$ go run main.go
-
项目启动以后,使用浏览器访问
http://localhost:8080/hello
就可以看到后端传回来的 json 数据了~
从上面的流程来看,使用 Golang 编写 web 程序还是非常简单的,尤其是相比较于 Java 的 SpringBoot ,免去了编写配置文件、使用注解处理请求等等繁杂的操作,我们只需要使用 gin.Default()
获取 server 对象,用它就可以处理各种请求。
Restful API
目前在前后端分离的架构中,前后端基本都是通过 Restful API 来进行交互。
REST 的含义就是客户端与 Web 服务器之间进行交互的时候,使用 HTTP 协议中的 4 个请求方法代表不同的动作:
- GET - 用来获取资源
- POST - 用来新建资源
- PUT - 用来更新资源
- DELETE - 用来删除资源
Gin 框架对 Restful 风格有着良好的支持,代码十分简单,示例如下:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/usr", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg": "查询用户信息成功"})
})
r.POST("/usr", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg": "创建用户信息成功"})
})
r.PUT("/usr", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg": "更新用户信息成功"})
})
r.DELETE("/usr", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg": "删除用户信息成功"})
})
r.Run()
}
响应页面
Gin 框架的 *gin.Context
实例封装了很多种响应方法 Json、HTML、String 等等。
-
返回给前端一个页面需要先加载静态页面,Gin 提供了两种方式:
r.LoadHTMLGlob("templates/*") // 加载指定目录下的所有页面 r.LoadHTMLFiles("templates/index.html") // 加载单个页面
-
调用
context.HTML()
方法返回一个页面给前端,其接受三个参数:状态码、页面地址、数据。
页面响应示例:
编写一个前端页面 index.html
,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Gin Demo</title>
</head>
<body>
<h1>Hello World !</h1>
<p>
获取后端传来的数据为:{{.msg}}
</p>
</body>
</html>
编写后端代码,main.go
文件如下:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
/* 加载静态页面 */
r.LoadHTMLGlob("templates/*")
/* 响应一个页面给前端 */
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"msg": "Golang Gin",
})
})
r.Run()
}
浏览器访问 http://localhost:8080/index
可以看到响应的页面以及后端传过来的数据:
PS: 如果前端页面引用了静态资源,还可以使用 r.Static()
方法进行加载。
获取请求参数
Gin 获取前端发送过来的参数十分简单。
🎈Get 请求:
Gin 获取 Get 请求发送的参数只要一行代码,支持问号拼接与 Restful 两种格式。
- 获取使用拼接字符串方式的 url 参数:
// url: localhost:8080/usr?id=001&name=jack r.GET("/usr", func(c *gin.Context) { id := c.Query("id") name := c.Query("name") })
- 获取使用 Restful 风格的 url 参数:
// url: localhost:8080/usr/001/jack r.GET("/usr/:id/:name", func(c *gin.Context) { id := c.Param("id") name := c.Param("name") })
🎈Post 请求:
前端一般使用 json 格式在 Post 请求中传递参数,Gin 获取 json 数据以后可以使用 Golang 自带的 Json 包进行反序列化操作拿到对应的数据。
r.POST("/usr", func(c *gin.Context) {
data, _ := c.GetRawData()
var m map[string]interface{}
_ = json.Unmarshal(data, &m)
})
路由 Router
Gin 的重定向操作也只需要一行代码就能搞定:
r.GET("/test", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "https:www.baidu.com")
})
访问页面不存在时可以使用 NoRoute
统一跳转至 404 页面:
r.NoRoute(func(c *gin.Context) {
c.HTML(http.StatusNotFound, "404.html", nil)
})
🎈路由组:
在 Gin 框架中提供了一个函数 Group
可以对路由进行分组管理,使用语法如下:
userGroup := r.Group("/usr")
{
userGroup.GET("/add", func(c *gin.Context) {
// ...
})
userGroup.POST("/login", func(c *gin.Context) {
// ...
})
userGroup.POST("/logout", func(c *gin.Context) {
// ...
})
}
自定义中间件
Gin 框架允许在处理请求的过程中加入钩子函数(Hook),也就是中间件,用来预处理一些公共的业务,比如登录授权、验证、分页等等。
Gin 的中间件是 gin.HandlerFunc
类型,示例如下:
func myHandler() (gin.HandlerFunc) {
return func(c *gin.Context) {
c.Set("userid", "123") // 在中间件中保存数据
c.Next() // 放行,执行后续逻辑
c.Abort() // 阻止调用后续处理的函数
}
}
在处理请求时使用自定义中间件:
r.GET("/usr", myHandler(), func(c *gin.Context) {
userid := c.MustGet("userid").(string) // 获取保存在中间件的数据
log.Println(userid)
})
🚀【参考】🚀