Introduce
Gin 是一个基于 Go 语言的 Web 框架,是一个 HTTP Web 服务器,采用了类似于 Echo 的编程框架。它可以用于构建高性能、可扩展的 Web 应用程序,提供了路由、参数绑定、JSON/XML 渲染、Cookie/命令行参数/环境变量等功能。
以下是 Gin 的主要特点:
- 高性能:Gin 大量采用了嵌套 HandlerFunc 的方法,不仅可以将多个中间件串联起来,还能 像树形结构一样可以灵活组合和嵌套,这种实现方式使得 Gin 在处理请求时效率非常高。
- 中间件插件机制:Gin 提供了丰富的中间件函数,并提供了实现自定义中间件的方法,可以轻松地对请求进行前置/后置处理,实现很多实用的功能,如日志记录、路由拦截、鉴权等。
- 路由:Gin 提供了 RESTful 风格的路由设置,支持 GET/POST/PUT/DELETE 等 HTTP 请求方法,支持参数路由、分组路由、静态文件服务器等功能。
- 参数绑定:Gin 提供了多种参数绑定的方法,支持绑定 URL 参数、表单参数、JSON 请求参数、XML 请求参数等,支持参数校验和数据转换。
- JSON/XML 渲染:Gin 自带了 JSON/XML 渲染功能,可以方便地将数据以 JSON/XML 格式返回给客户端。
- 异常处理:Gin 提供了强大的异常处理机制,可以方便地捕获全局异常、HTTP 异常、路由异常等,并提供了友好的错误信息显示方式。
- 多种渲染模版:Gin 支持多种模板引擎,如 html/template、amber、handlebars、jet、mustache、pongo2 等,可以根据需要灵活选择。
Install
-
可以使用 go get 命令安装。
go get -u github.com/gin-gonic/gin -
如果使用了 IDE,可以直接在源代码中引入上述包,IDE 可以自动下载。
框架的简单使用
创建一个服务
创建服务是建立一个 Web 服务的第一步,使用以下代码创建一个服务。
ginServer := gin.Default()
服务创建成功后,会获得一个 *gin.Engine 类型的变量 ginServer,之后就可以通过它对服务进行设置、控制。
简单设置
自定义网站图标
在创建服务后,可以对其进行一些设置,比如可以通过使用 Gin 的 favicon 中间件来为应用程序添加自定义的网站图标
ginServer.Use(favicon.New("./GinDemo/main/favicon.jpg"))
具体来说,当 Web 应用程序启动后,用户在浏览器中访问该应用时,浏览器会自动请求获取网站的 favicon.ico 文件(即网站图标文件),如果没有设置该文件,则会产生一个 404 错误。当我们将该中间件添加到 ginServer 中之后,它会拦截所有请求,如果该请求为 GET 方法,并且请求 URL 路径为 "/favicon.ico",则会将指定的网站图标文件作为响应数据返回给客户端。这样就可以避免浏览器产生 404 错误,同时为 Web 应用程序提供了一个自定义的网站图标。
设置中间件(拦截器)
过滤器设计模式的应用,可以编写一个自定义中间件,并进行注册,依次对请求作某些处理。
func myHandler() gin.HandlerFunc {
return func(context *gin.Context) {
context.Set("user_session", "user")
context.Abort()
//context.Next()
}
}
上面自定义了一个处理函数,context.Abort() 可以将请求拦截,context.Next() 表示请求通过。gin.Context 类型可以类比 Java 中的 HttpServletRequest,可以通过此类型的变量获取请求的相关信息,包括请求头、请求参数、请求体等。当然,gin.Context 提供了一些 Gin 框架特有的方法和属性。
当定义好了处理函数,可以使用 ginServer.Use(myHandler()) 语句注册该中间件,那么此服务的所有请求都会被该中间件拦截处理。也可以设置拦截某个特定的请求,设置方法在下文讲述。
加载相关文件
如果某个请求需要返回一个 HTML 页面等,则需要在服务中加载相应的 HTML 页面以及相关资源文件。
// 加载静态文件 html
ginServer.LoadHTMLGlob("./GinDemo/templates/*")
// 加载资源文件 css js
ginServer.Static("/GinDemo/static", "./GinDemo/static")
定义请求
这是最关键的部分,即设置请求路径,使得可以通过该路径访问相应的资源或服务。
GET
ginServer.GET("/hello", func(context *gin.Context) {
context.JSON(200, gin.H{
"message": "hello world",
})
})
上面的代码可以实现设置一个路径为 /hello 的 GET 请求,context.JSON 可以向请求发起者返回一个 JSON 格式的数据,使用 gin.H 封装。
Gin 也支持 Restful API,下面给出一个例子。
ginServer.GET("/user/:name/:age", func(context *gin.Context) {
name := context.Param("name")
age := context.Param("age")
fmt.Println(name, age)
// 返回数据
context.JSON(200, gin.H{
"message": "get success",
"name": name,
"age": age,
})
})
如果要相应一个 HTML 页面,则可以使用下面的方式。注意,返回的内容必须要先注册。
ginServer.GET("/index", func(context *gin.Context) {
context.HTML(http.StatusOK, "index.html", gin.H{
"name": "zhangsan",
})
})
POST
表单提交是很常用的请求,下面给出一个简单的表单处理的例子。
ginServer.POST("/form", func(context *gin.Context) {
// request body
username := context.PostForm("username")
password := context.PostForm("password")
fmt.Println(username, password)
// 可以写校验逻辑
// 返回数据
context.JSON(http.StatusOK, gin.H{
"username": username,
"password": password,
})
})
如果请求者发送了 JSON 格式的数据,可以通过下面的代码处理。
ginServer.POST("/json", func(context *gin.Context) {
// request body
body, err := context.GetRawData()
if err != nil {
fmt.Println("get raw data failed, err: ", err)
return
}
var m map[string]interface{}
err = json.Unmarshal(body, &m)
if err != nil {
fmt.Println("unmarshal failed, err: ", err)
return
}
fmt.Println(m)
// 返回数据
context.JSON(http.StatusOK, m)
})
PUT
ginServer.PUT("/put", func(context *gin.Context) {
// 获取参数
username := context.Query("username")
password := context.Query("password")
fmt.Println(username, password)
// 返回数据
context.JSON(200, gin.H{
"message": "put success",
})
})
DELETE
ginServer.DELETE("/delete", func(context *gin.Context) {
// 获取参数
username := context.Query("username")
password := context.Query("password")
fmt.Println(username, password)
// 返回数据
context.JSON(200, gin.H{
"message": "delete success",
})
})
路由分组
当项目规模增加,需要定义的请求就会增加,使用路由分组可以让文件结构变得更加清晰,提升代码的可读性。这个与在 Java Web 中通过编写一个 Base Servlet,其他的 Servlet 继承 Base Servlet 实现的功能一样,但是从下面的代码可以看出,Go 实现起来要简易许多。
v1 := ginServer.Group("/v1")
{
v1.GET("/login", func(context *gin.Context) {
context.JSON(200, gin.H{
"message": "v1 login",
})
})
v1.GET("/submit", func(context *gin.Context) {
context.JSON(200, gin.H{
"message": "v1 submit",
})
})
}
使用 ginServer.Group() 可以创建一个请求根路径,然后在下面的代码体中写子路径,然后就可以通过两个路径拼接来访问资源或服务了。
后记
学习过 Java Web 开发的相关技术,但是与 Go 语言通过 Gin 开发后端相比还是复杂很多,Go 提供的库和 Gin 框架提供的属性和方法大大方便了 Web 应用、服务的开发。