gin.Engine
结构体
gin.Engine
是 Gin 框架中最重要的结构体,主要提供了以下功能:
-
路由管理:注册和调度路由请求。
-
中间件管理:添加、调用全局或局部中间件。
-
服务启动:启动 HTTP 或 HTTPS 服务。
-
静态资源管理:提供静态文件服务。
-
错误处理:捕获和处理应用中的错误
gin.New()
和 gin.Default()
Gin 提供了两个用于创建 Engine
实例的方法:
-
gin.New()
:-
创建一个没有默认中间件的
Engine
实例。你需要手动添加所有中间件(例如日志和恢复中间件)。
r := gin.New()
-
-
gin.Default()
:-
创建一个带有默认中间件的
Engine
实例。默认中间件包括 Logger(日志记录)和 Recovery(崩溃恢复)。
r := gin.Default()
在大多数情况下,使用
gin.Default()
是比较方便的,因为它提供了一些基本的中间件,适合快速开发和调试。 -
Engine
的核心方法
1. 路由注册
-
GET/POST/PUT/DELETE/...
-
用于注册不同的 HTTP 请求方法。每个方法对应一个处理函数。
r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) })
-
-
Any()
: -
允许你为同一个路径注册所有的 HTTP 方法,
GET/POST/PUT/DELETE/...
。
r.Any("/any", func(c *gin.Context) { c.String(200, "Any method accepted") })
-
NoRoute()
: -
注册一个处理未匹配路径的路由处理函数,通常用于自定义 404 错误页面。
r.NoRoute(func(c *gin.Context) { c.JSON(404, gin.H{"message": "Not Found"}) })
2. 中间件管理
-
Use()
:-
添加全局中间件,所有请求都会经过这些中间件。
r.Use(gin.Logger(), gin.Recovery())
-
3. 启动服务
-
Run()
:-
启动 HTTP 服务,默认监听在
:8080
端口。可以传入其他端口号或地址参数。
r.Run() // 监听并服务于 0.0.0.0:8080
-
-
RunTLS()
:-
启动 HTTPS 服务,要求提供 SSL 证书和密钥。
r.RunTLS(":8080", "cert.pem", "key.pem")
-
-
RunUnix()
:-
启动 Unix 套接字服务。
r.RunUnix("/tmp/gin.sock")
-
4. 静态文件和模板
-
Static()
:-
提供静态文件服务。可以将一个文件夹映射到一个路由前缀。
r.Static("/assets", "./assets")
静态文件通常指的是前端资源文件,如图片、CSS、JavaScript 文件等。Gin 提供了
Static()
方法,可以将一个目录映射到一个路由前缀,这样用户可以通过指定的 URL 路径访问这些文件。-
/assets
:URL 路径前缀。访问静态文件时,URL 必须以/assets
开头。例如,http://localhost:8080/assets/logo.png
会访问./assets/logo.png
文件。 -
./assets
:本地文件系统中的目录路径。这个目录包含了静态资源文件,例如图片、CSS 文件等。
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // 提供静态文件服务,将本地的 ./assets 目录映射到 /assets 路径 r.Static("/assets", "./assets") r.GET("/index", func(c *gin.Context) { c.String(200, "Welcome to the Index Page") }) r.Run(":8080") }
假设
./assets
目录中有一个名为logo.png
的图片文件,访问http://localhost:8080/assets/logo.png
会返回这张图片。 -
-
LoadHTMLGlob()
:-
加载模板文件并渲染 HTML。支持通配符。
r.LoadHTMLGlob("templates/*")
在处理请求时,可以使用
c.HTML()
来渲染模板。r.GET("/index", func(c *gin.Context) { c.HTML(200, "index.tmpl", gin.H{"title": "Main website"}) })
Gin 也支持服务器端渲染 HTML 模板,这样你可以生成动态网页。模板文件通常是
.tmpl
或.html
文件,它们包含 HTML 和动态内容的占位符。-
templates/\*
:这个路径是模板文件的通配符,意味着 Gin 会加载templates
目录下所有的模板文件。你可以在模板文件中使用 Go 的模板语法来动态生成内容。
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // 加载模板文件,支持通配符,表示加载 templates 目录下所有文件 r.LoadHTMLGlob("templates/*") r.GET("/index", func(c *gin.Context) { // 渲染模板 index.tmpl,并传递一个包含动态数据的 map c.HTML(200, "index.tmpl", gin.H{ "title": "Main website", }) }) r.Run(":8080") }
假设你有一个模板文件
templates/index.tmpl
,内容如下:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ .title }}</title> </head> <body> <h1>Welcome to {{ .title }}</h1> </body> </html>
在这个例子中,
c.HTML()
函数会渲染模板文件index.tmpl
,并将gin.H{"title": "Main website"}
中的数据传递给模板。模板中的占位符{{ .title }}
将被替换为"Main website"
。 -
5. 错误处理
-
HandleContext()
:-
手动触发请求处理流程。在某些情况下,你可能需要手动处理上下文并将其传递给
Engine
。
r.HandleContext(c)
-
-
AbortWithError()
:-
中止当前请求并记录错误。通常用于提前终止请求并返回错误信息。
c.AbortWithError(500, errors.New("an error occurred"))
-
路由与路由组
Gin 提供了灵活的路由管理功能,你可以通过 GET
、POST
、PUT
、DELETE
等方法定义路由。路由组可以将相关的路由组织在一起,方便管理。
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // 简单的路由定义 r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) // 路由组 v1 := r.Group("/v1") { v1.GET("/users", func(c *gin.Context) { // 处理 "/v1/users" 路由 }) v1.GET("/orders", func(c *gin.Context) { // 处理 "/v1/orders" 路由 }) } r.Run() }
中间件
中间件是 Gin 框架的核心功能,用于在请求处理之前或之后执行特定操作。你可以定义全局中间件或为特定路由组定义中间件。
package main import ( "github.com/gin-gonic/gin" "log" "time" ) // 定义一个简单的日志中间件 func Logger() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() // 处理请求 c.Next() // 请求完成后执行 duration := time.Since(start) log.Printf("Request processed in %s", duration) } } func main() { r := gin.Default() // 使用全局中间件 r.Use(Logger()) r.GET("/test", func(c *gin.Context) { c.String(200, "Hello, Gin!") }) r.Run() }
gin中自带一部分中间件比如gin.Logger()
和gin.Recovery()
gin.Logger()
和 gin.Recovery()
是 Gin 框架中两个非常常用的全局中间件,它们用于处理日志记录和程序崩溃恢复。它们默认情况下会在 gin.Default()
初始化时自动加载。
1. gin.Logger()
gin.Logger()
是一个中间件,用于记录每个 HTTP 请求的日志信息,包括请求的路径、请求方法、状态码、处理时间等。
package main import ( "github.com/gin-gonic/gin" ) func main() { // 使用 gin.Logger() 中间件 r := gin.New() r.Use(gin.Logger()) r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run(":8080") }
当你发送请求到 /ping
路径时,控制台会打印类似如下的日志:
[GIN] 2024/08/25 - 12:34:56 | 200 | 5.1234ms | 127.0.0.1 | GET /ping
日志记录了请求时间、状态码、请求处理时间、客户端 IP 地址、请求方法和路径等信息。
2. gin.Recovery()
gin.Recovery()
是一个中间件,用于在程序出现 panic 时进行恢复,避免程序崩溃并返回 500 错误。Gin 提供了 Recovery
中间件来捕获 panic 并记录错误信息,然后返回一个友好的 HTTP 500 错误页面或 JSON 响应,而不会导致整个服务挂掉。
package main import ( "github.com/gin-gonic/gin" ) func main() { // 使用 gin.Recovery() 中间件 r := gin.New() r.Use(gin.Recovery()) r.GET("/panic", func(c *gin.Context) { // 模拟一个会引发 panic 的操作 panic("Something went wrong!") }) r.Run(":8080") }
当访问 /panic
路径时,程序会引发 panic。由于使用了 gin.Recovery()
中间件,程序不会崩溃,而是捕获 panic 并返回 500 错误。控制台会记录如下的错误日志:
[GIN] 2024/08/25 - 12:34:56 | 500 | 10.5678ms | 127.0.0.1 | GET /panic [GIN-debug] [Recovery] 2024/08/25 - 12:34:56 panic recovered: runtime error: Something went wrong!
gin.context
在 Gin 框架中,gin.Context
是核心结构体,它封装了 HTTP 请求和响应,并提供了丰富的功能来处理 HTTP 请求的各种操作。gin.Context
提供了对路由、参数、请求数据、中间件等方面的管理,是 Gin 中用于处理请求的主要对象。
gin.Context
的主要功能
1. 获取请求数据
-
查询参数:
-
使用
Query()
方法获取 URL 中的查询参数。 -
如果查询参数不存在,可以指定默认值。
c.Query("name") // 获取查询参数 name 的值 c.DefaultQuery("name", "default_name") // 获取查询参数 name 的值,若不存在则返回默认值 "default_name"
-
-
表单参数:
-
使用
PostForm()
方法获取 POST 请求中的表单数据。
c.PostForm("name") c.DefaultPostForm("name", "default_name")
-
-
路径参数:
-
使用
Param()
方法获取路由中定义的路径参数。
c.Param("id") // 例如: 路由定义为 "/user/:id"
-
-
JSON 数据:
-
使用
ShouldBindJSON()
或BindJSON()
解析 JSON 数据并绑定到结构体。
var jsonData MyStruct if err := c.ShouldBindJSON(&jsonData); err != nil { c.JSON(400, gin.H{"error": err.Error()}) return }
-
2. 设置和获取上下文中的数据
-
设置数据:
-
使用
Set()
方法在gin.Context
中存储数据,供后续的处理中使用。
c.Set("key", "value")
-
-
获取数据:
-
使用
Get()
方法获取上下文中的数据。还可以使用GetString()
、GetInt()
等辅助方法进行类型转换。
value, exists := c.Get("key")
-
3. 响应处理
-
返回 JSON 响应:
c.JSON(200, gin.H{ "message": "Hello, World!", })
-
返回字符串响应:
c.String(200, "Hello, %s", name)
-
返回文件响应:
c.File("./path/to/file")
-
返回重定向:
c.Redirect(302, "/new_path")
4. 中间件处理
gin.Context
中的中间件功能允许你在处理请求之前或之后执行一些操作,例如日志记录、授权、请求修改等。
-
在中间件中处理:
func MyMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // 执行操作,例如设置上下文中的数据 c.Set("example", "value") // 执行下一步操作 c.Next() // 在请求处理后执行操作 status := c.Writer.Status() log.Println("Status:", status) } }
-
中止请求:
-
使用
Abort()
方法停止请求的进一步处理,并立即返回响应。
c.AbortWithStatus(403)
-
5. 控制流管理
gin.Context
提供了对请求生命周期的控制,包括中止请求、跳过中间件等。
-
Next()
:-
Next()
方法让控制流继续到下一个中间件或最终处理器。通常用于中间件链中。
c.Next()
-
-
Abort()
和AbortWithStatus()
:-
Abort()
用于停止控制流,并且不会继续调用后续的中间件或处理器。 -
AbortWithStatus()
可以在中止请求的同时返回 HTTP 状态码。
c.Abort() c.AbortWithStatus(400)
-
6. 文件上传
Gin 提供了对文件上传的简便支持,允许通过 gin.Context
直接处理文件上传请求。
// 单文件上传 file, _ := c.FormFile("file") c.SaveUploadedFile(file, "./uploads/"+file.Filename) // 多文件上传 form, _ := c.MultipartForm() files := form.File["files"] for _, file := range files { c.SaveUploadedFile(file, "./uploads/"+file.Filename) }
context.Context
与 gin.Context
gin.Context
实现了 Go 语言的 context.Context
接口,因此你可以在 Gin 的上下文中使用标准的 context.Context
方法,如 Deadline()
、Done()
、Err()
和 Value()
。这意味着你可以利用 gin.Context
的功能在并发环境下传递取消信号、超时等信息。
r.GET("/timeout", func(c *gin.Context) { // 创建一个带超时的 context ctx, cancel := context.WithTimeout(c.Request.Context(), 2*time.Second) defer cancel() select { case <-time.After(3 * time.Second): // 模拟长时间运行任务 c.String(http.StatusOK, "Completed after 3 seconds") case <-ctx.Done(): // 超时或取消 c.String(http.StatusRequestTimeout, "Request timed out") } })