要实现一个 API
服务器,首先要考虑两个方面:API
风格和媒体类型。Go
语言中常用的 API
风格是 RPC
和 REST
,常用的媒体类型是 JSON
、XML
和 Protobuf
。在 Go API
开发中常用的组合是 gRPC+Protobuf
和 REST+JSON
。
Gin
是一个用 Go
(Golang
)编写的 web
框架。要安装 Gin
包,你需要先安装 Go
并设置你的 Go
工作空间。
首先需要安装 Go
(需要 1.15 以上版本),然后你可以使用下面的 Go
命令来安装 Gin
。
go get -u github.com/gin-gonic/gin
创建一个目录,并初始化,此处我们使用 go mod
初始化一个工程。
$ mkdir webserver
$ cd webserver
$ go mod init webserver
go: creating new go.mod: module webserver
新建 main.go
代码,并填写如下内容:
package main
import "github.com/gin-gonic/gin"
func pingResponse(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
}
func main() {
r := gin.Default()
// 表示 HTTP 的 GET 方法请求,如果通过 POST 方法发送请求将不会得到正确的响应。
r.GET("/ping", pingResponse)
r.Run() // listen and serve on 0.0.0.0:8080
}
其中:
Default()
默认情况下,返回一个已经连接了日志和恢复中间件的引擎实例。GET
第一个参数为相对路径,第二个参数为该相对路径对应的响应函数。*gin.Context
上下文是 gin
中最重要的部分。它允许我们在中间件之间传递变量,管理流程,验证请求的 JSON
,并渲染一个 JSON
响应。gin.H
是 map[string]interface{}
的快捷方式,用于定义 key-value
结构。r.Run()
将路由器连接到 http.Server
上,并开始监听和服务 HTTP
请求。它是http.ListenAndServe(addr, router)
的一个快捷方式,注意:除非发生错误,否则这个方法将无限期地阻塞调用的 goroutine
。执行该段代码
$ go run main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /ping --> main.pingResponse (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
发送 HTTP
的 Get
请求
$ curl http://127.0.0.1:8080/ping
{"message":"pong"}
通过上面代码也可以知道,/ping
是访问的地址,而 func(c *gin.Context)
定义了处理程序 HandlerFunc
,类型定义如下:
type HandlerFunc func(*gin.Context)
Context
是 Gin
框架中最重要的结构体,它允许开发人员在中间件之间传递变量,管理流,验证请求并呈现响应等。
通过 Context
,开发人员还可以处理参数变量,文件上传等,上面使用 Context
的 c.JSON()
方法返回状态码以及响应的字符串,用户在浏览器中可看到响应的字符串。除了字符串,还可以返回 String
、HTML
等形式,这里称为渲染 render
。
也可以定制一个服务,然后运行 ListenAndServe()
,如下所示:
func main() {
router := gin.Default()
s := &http.Server{
Addr: ":8080",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}
此时 gin.Default()
方法产生的引擎实例 router
作为服务的 Handler
,还可以指定端口等定制服务配置,配置好服务后就可以运行 ListenAndServe()
了。
Gin
框架中按主要功能可以划分为以下几个部分:
Engine
)RouterGroup
)Context
)Render
)Binding
)Engine
是 Gin
框架中非常核心的结构体,由 Engine
生成框架的实例,它包含多路复用器,中间件和路由信息表等。Gin
提供了两种方法来生成一个 Engine
实例:
router := gin.New()
和
router := gin.Default()
上面代码中的 router
就是一个 Engine
实例,这两个函数最终都会生成一个 Engine
实例。
唯一区别是 gin.Default()
函数在 gin.New()
函数基础上,使用 gin.Use()
函数,加入了日志中间件 Logger()
和异常恢复中间件 Recovery()
这两个中间件。在 Gin
中,中间件一般情况下会对每个请求都会有效。
在 Gin
框架中,系统自带了异常恢复 Recovery
中间件,这个中间件在处理程序出现异常时会在异常链中的任意位置恢复程序, 并打印堆栈的错误信息。
Gin
框架支持 GET
、POST
、PUT
、PATCH
、HEAD
、OPTIONS
、DELETE
等 HTTP
方法,所以 HTTP
请求传递到 Gin
框架时,HTTP
请求路由器会根据具体 HTTP
方法先确定该方法的路由信息表,再匹配路径来返回不同的处理程序信息。
下面代码表示 HTTP
的 GET
方法请求,如果通过 POST
方法发送请求将不会得到正确的响应。换句话说,如果请求方法不对,在路由表中根本就找不到合适的处理程序。
router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})