路由
在 Web 应用开发中,路由的作用是根据不同的 URL 请求,将其映射到相应的处理函数上,以实现不同的业务逻辑。Gin 框架提供了丰富且灵活的路由功能,使开发者能够轻松应对各种复杂的路由需求。
1. 基础路由
Gin 的路由处理非常直观,下面展示了一些基本的路由用法。
1.1 处理 GET 请求
GET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据.
r.GET("/hello", func(c *gin.Context) {c.String(200, "Hello, world!")
})
上述代码定义了一个简单的 GET 请求路由。当客户端向服务器发起对/hello
路径的 GET 请求时,Gin 框架会捕获该请求,并执行对应的匿名函数。在该匿名函数中,通过c.Stri``ng(200, "``Hello, world!")
向客户端返回 HTTP 状态码 200(表示请求成功),以及响应内容 “Hello, world!” 。
1.2 处理 POST 请求
POST方法用于将实体提交到指定的资源,通常会导致在服务器上的状态变化
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.POST("/post", func(c *gin.Context) {var json struct {Name string `json:"name"`Age int `json:"age"`}if err := c.ShouldBindJSON(&json); err != nil {c.JSON(400, gin.H{"error": err.Error()})return}c.JSON(200, gin.H{"message": "Data received", "name": json.Name, "age": json.Age})})r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
代码实现了对 POST 请求的处理。当接收到对/post
路径的 POST 请求时,首先定义一个结构体json
,用于存储从请求体中解析出来的 JSON 数据。然后使用c.ShouldBindJSON(&json)
方法尝试将请求体中的 JSON 数据绑定到json
结构体上。
如果绑定过程中出现错误,如请求体格式不正确,就会返回 HTTP 状态码 400(表示客户端请求错误),并将错误信息以 JSON 格式返回给客户端。若绑定成功,则返回 HTTP 状态码 200,以及包含成功消息和解析出的name
字段和age
字段的 JSON 数据。
1.3 处理 PUT 请求
PUT方法用请求有效载荷替换目标资源的所有当前表示
// 处理 PUT 请求r.PUT("/update", func(c *gin.Context) {c.JSON(200, gin.H{"message": "PUT request received"})})
1.4 处理 DELETE 请求
// 处理 DELETE 请求r.DELETE("/delete", func(c *gin.Context) {c.JSON(200, gin.H{"message": "DELETE request received"})})
2.处理动态路由参数
动态路由参数允许在 URL 中包含可变部分,这些部分可以在处理函数中获取。
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/user/:id", func(c *gin.Context) {id := c.Param("id")c.String(200, "User ID: %s", id)})r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
代码展示了如何处理带有动态路由参数的请求。在路由定义中,/user/:id
表示路径中的:id
是一个动态参数。当客户端请求类似/user/123
这样的路径时,Gin 框架会将123
作为id
参数的值。在处理函数中,通过c.Param("id")
获取这个参数值,并将其作为响应内容的一部分返回给客户端,
请求路径:
http://localhost:8080/user/12
返回数据:
User ID: 123
3.多个动态路由参数
可以在一个路由中包含多个动态参数。
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/user/:id/book/:book_id", func(c *gin.Context) {id := c.Param("id")bookID := c.Param("book_id")c.String(200, "User ID: %s, Book ID: %s", id, bookID)})r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
此示例展示了如何处理包含多个动态路由参数的请求。在/user/:id/book/:book_id
这个路由中,有两个动态参数:id
和:book_id
。当客户端请求如/user/1/book/5
这样的路径时,1
会被赋值给id
,5
会被赋值给bookID
。
在处理函数中,分别通过c.Param("id")
和c.Param("book_id")
获取这两个参数值,并将它们作为响应内容返回给客户端,即返回 “User ID: 1, Book ID: 5” 。
请求路径:
http://localhost:8080/1/5
返回数据:
User ID: 1, Book ID: 5
4.路由分组
Gin 允许开发者为路由创建分组,这在实际项目开发中非常实用。通过Group()
方法,可以将相关的路由组织在一起,便于管理和维护,同时还能为不同的路由组添加特定的中间件。
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()user := r.Group("/user"){user.GET("/info", func(c *gin.Context) {c.String(200, "user info")})user.GET("/login", func(c *gin.Context) {c.String(200, "user login")})}r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
上述代码创建了一个名为user
的路由组,该路由组的所有路由都以/user
为前缀。在这个路由组中,定义了两个 GET 请求路由:/user/info
和/user/login
,分别返回 “user info” 和 “user login”。
此外,还可以在路由组中使用中间件,例如添加身份验证的中间件:
user := r.Group("/user", AuthMiddleware())
这样,当需要对这组路由进行统一管理或添加共同的中间件时,就可以直接在user
路由组上进行操作,而无需对每个路由单独处理。
5.通配符路由
通配符路由可以匹配任意路径,使用 *
作为通配符。
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 定义通配符路由r.GET("/static/*filepath", func(c *gin.Context) {// 获取通配符匹配的路径filepath := c.Param("filepath")c.String(200, "Static file path: %s", filepath)})r.Run(":8080")
}
此示例展示了通配符路由。*filepath
是通配符参数,它可以匹配 /static/
后面的任意路径。
请求路径:
http://localhost:8080/static/c/go/bin
返回数据:
Static file path: /c/go/bin
6.NoRotu 处理 404 错误
当客户端请求的路径没有匹配到任何路由时,Gin 会返回 404 错误。可以自定义 404 错误处理函数。
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 定义自定义的 404 错误处理函数r.NoRoute(func(c *gin.Context) {c.JSON(404, gin.H{"error": "Page not found"})})r.Run(":8080")
}
r.NoRoute
方法用于定义 404 错误处理函数,当请求的路径没有匹配到任何路由时,会执行该函数。
正常我们都是使用一个404页面来提示用户,我们可以用下面的方法来实现:
在项目中创建tpl
目录,该目录下创建notpage.html
:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>404 - Page Not Found</title><style>body {font-family: Arial, sans-serif;background-color: #f4f4f4;text-align: center;padding-top: 100px;}h1 {font-size: 60px;color: #333;}p {font-size: 20px;color: #666;}a {color: #007BFF;text-decoration: none;}a:hover {text-decoration: underline;}</style>
</head><body>
<h1>404</h1>
<p>Oops! The page you're looking for doesn't exist.</p>
<p>You can <a href="/">go back to the homepage</a> or try another search.</p>
</body></html>
修改mian.go:
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 设置 HTML 模板文件的路径r.LoadHTMLGlob("tpl/*")// 定义自定义的 404 错误处理函数/*r.NoRoute(func(c *gin.Context) {c.JSON(404, gin.H{"error": "Page not found"})})*/r.NoRoute(func(c *gin.Context) {c.HTML(200, "notpage.html", gin.H{})})r.Run(":8080")
}
当执行任何不存在的路由就会返回以下页面
7.路由优先级
Gin 根据路由的定义顺序匹配请求的路径,较为精确的路径会先匹配。