Gin从入门到精通 (三)路由
路由
在 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 main
import (
"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 main
import (
"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 main
import (
"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 main
import (
"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 main
import (
"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 main
import (
"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 main
import (
"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 根据路由的定义顺序匹配请求的路径,较为精确的路径会先匹配。