Gin 是一个用 Go 语言编写的轻量级 Web 框架,以其高性能、简洁易用和良好的扩展性而受到广泛欢迎。
安装与初始化
在使用 Gin 之前,你需要安装它。可以使用以下命令进行安装:
go get -u github.com/gin-gonic/gin
在代码中初始化 Gin 引擎的示例:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
// 创建一个默认的 Gin 引擎,包含日志和恢复中间件
r := gin.Default()
// 启动服务器,监听 8080 端口
r.Run(":8080")
}
gin.Default()
方法会自动帮你配置 Logger
和 Recovery
中间件。Logger
用于记录请求日志,Recovery
用于捕获并处理 panic
,防止程序因 panic
而崩溃。 想要自定义中间件的顺序和配置,也可以手动配置 Recovery
中间件。示例代码如下
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
// 创建一个空的 Gin 引擎
r := gin.New()
// 手动添加 Recovery 中间件
r.Use(gin.Recovery())
r.GET("/", func(c *gin.Context) {
// 模拟一个 panic
panic("Something went wrong!")
})
r.Run(":8080")
}
在这个例子中,使用 gin.New()
创建了一个空的 Gin 引擎,然后通过 r.Use(gin.Recovery())
手动添加了 Recovery
中间件。同样,当访问 /
路由触发 panic
时,程序不会崩溃
你还可以自定义 Recovery
中间件的行为,例如自定义错误处理逻辑和响应信息。示例代码如下:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
"runtime/debug"
)
func customRecovery() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
// 打印错误信息和堆栈跟踪
debug.PrintStack()
// 返回自定义的错误响应
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Internal Server Error",
})
// 终止当前请求处理
c.Abort()
}
}()
// 继续处理请求
c.Next()
}
}
func main() {
r := gin.New()
// 使用自定义的 Recovery 中间件
r.Use(customRecovery())
r.GET("/", func(c *gin.Context) {
panic("Something went wrong!")
})
r.Run(":8080")
}
路由
Gin 支持多种 HTTP 方法(如 GET、POST、PUT、DELETE 等)的路由设置。
基本路由示例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 定义一个 GET 请求的路由
r.GET("/hello", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Hello, World!",
})
})
r.Run(":8080")
}
在上述代码中,我们定义了一个 /hello
的 GET 请求路由,当客户端访问该路由时,会返回一个 JSON 格式的响应。
路由参数
Gin 支持在路由中使用参数。
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 定义一个带有参数的路由
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"user_id": id,
})
})
r.Run(":8080")
}
这里的 :id
是一个参数,客户端访问 /users/123
时,服务器会将 123
作为 id
参数进行处理。
中间件
中间件是 Gin 中非常重要的特性,它可以在请求处理前后执行一些操作,如日志记录、身份验证等。
自定义中间件示例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 自定义中间件函数
func myMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 在请求处理前执行操作
c.Set("key", "value")
// 继续处理请求
c.Next()
// 在请求处理后执行操作
}
}
func main() {
r := gin.Default()
// 使用自定义中间件
r.Use(myMiddleware())
r.GET("/test", func(c *gin.Context) {
value, exists := c.Get("key")
if exists {
c.JSON(http.StatusOK, gin.H{
"message": "Middleware value: " + value.(string),
})
}
})
r.Run(":8080")
}
在这个例子中,我们定义了一个自定义中间件 myMiddleware
,它在请求处理前设置了一个键值对,在处理 /test
路由时可以获取到这个值。
分组路由
分组路由可以将一组相关的路由进行分组管理,方便代码组织和维护。
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 创建一个路由组
v1 := r.Group("/v1")
{
v1.GET("/users", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"version": "v1",
"resource": "users",
})
})
v1.GET("/posts", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"version": "v1",
"resource": "posts",
})
})
}
r.Run(":8080")
}
这里我们创建了一个 /v1
的路由组,将 /v1/users
和 /v1/posts
路由放在这个组中。
错误处理
Gin 提供了简单的错误处理机制,可以方便地处理请求过程中出现的错误。
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default() // gin.Default() 已经包含了 Recovery 中间件
r.GET("/panic", func(c *gin.Context) {
// 模拟一个 panic
panic("Panic occurred")
})
r.Run(":8080")
}
当使用 gin.Default()
创建 Gin 引擎时,会自动包含 Logger
和 Recovery
中间件。Recovery
中间件会捕获 panic
,并返回一个 500 状态码的错误响应。
c.Abort()
c.Abort()
方法的主要功能是停止当前请求在中间件链中的继续执行,也就是说,后续还未执行的中间件和处理函数都不会再被调用。
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func middleware1(c *gin.Context) {
// 模拟一些处理逻辑
c.JSON(http.StatusOK, gin.H{"message": "Middleware 1 executed"})
// 终止请求处理流程
c.Abort()
}
func middleware2(c *gin.Context) {
// 由于 middleware1 中调用了 c.Abort(),此函数不会被执行
c.JSON(http.StatusOK, gin.H{"message": "Middleware 2 executed"})
}
func main() {
r := gin.Default()
r.GET("/", middleware1, middleware2)
r.Run(":8080")
}
在这个例子中,当客户端访问根路径 /
时,middleware1
会先被执行,在 middleware1
里调用了 c.Abort()
,这就导致 middleware2
不会被执行。
在错误处理的场景中,c.Abort()
常常和 c.JSON()
一起使用,以此返回错误响应并终止请求处理。
静态文件服务
Gin 可以方便地提供静态文件服务,如 HTML、CSS、JavaScript 等文件。
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 提供静态文件服务
r.Static("/static", "./static")
r.Run(":8080")
}
这里将 ./static
目录下的文件映射到 /static
路径下,客户端可以通过 /static
访问这些静态文件。
使用 Gin 框架实现文件上传和下载
Gin 框架提供了更简洁的 API 来处理文件上传和下载
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"log"
"os"
)
func uploadFile(c *gin.Context) {
// 单文件上传
file, err := c.FormFile("file")
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
// 创建上传目录
if _, err := os.Stat("./uploads"); os.IsNotExist(err) {
err := os.MkdirAll("./uploads", 0755)
if err != nil {
log.Fatal(err)
}
}
// 保存文件
filePath := "./uploads/" + file.Filename
if err := c.SaveUploadedFile(file, filePath); err != nil {
c.JSON(500, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, gin.H{
"message": fmt.Sprintf("'%s' uploaded successfully", file.Filename),
})
}
func main() {
r := gin.Default()
// 定义上传文件的路由
r.POST("/upload", uploadFile)
// 启动服务器
if err := r.Run(":8080"); err != nil {
log.Fatal(err)
}
}
package main
import (
"github.com/gin-gonic/gin"
"log"
)
func downloadFile(c *gin.Context) {
filePath := "./uploads/test.txt" // 替换为实际要下载的文件路径
c.File(filePath)
}
func main() {
r := gin.Default()
// 定义下载文件的路由
r.GET("/download", downloadFile)
// 启动服务器
if err := r.Run(":8080"); err != nil {
log.Fatal(err)
}
}