Это 13-й день моего участия в августовском испытании обновлений.Подробности о событии:Испытание августовского обновления
Gin — это стандартная структура веб-сервиса, соответствующая спецификации интерфейса Restful API, а его библиотека маршрутизации реализована на основе httproute.
Этот раздел начнется с маршрутизации Gin и подробно описывает, как реализовать Gin в различных сценариях маршрутизации.
базовая маршрутизация
Gin поддерживает GET, POST, PUT, PATCH, DELETE, OPTIONS и другие типы запросов.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
route := gin.Default()
// 设置一个get请求,其URL为/hello,并实现简单的响应
route.GET("/get", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "this is a get method response!",
})
})
// 具体实现可单独定义一个函数
route.POST("/post", postHandler)
route.PUT("/put", func(c *gin.Context) {
})
route.PATCH("/patch", func(c *gin.Context) {
})
route.DELETE("/delete", func(c *gin.Context) {
})
// ……
route.Run()
}
func postHandler(c *gin.Context) {
c.JSON(http.StatusOK, "this is a post method response!")
}
обработка параметров
параметр пути
доступный*gin.Context
Функция Param получает параметры в пути запроса, а параметры в пути пути начинаются с:
начните с:/user/:name
, способный сопоставить путь/user/xx
.
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Username string `json:"username"`
Sex string `json:"sex"`
Age int `json:"age"`
Labels []string `json:"lalels"`
}
func main() {
route := gin.Default()
users := []User{
{
Username: "xcbeyond",
Sex: "男",
Age: 18,
Labels: []string{"年轻", "帅"},
},
}
// 请求path中存在参数
route.GET("/user/:name", func(c *gin.Context) {
// 获取请求path中的参数
name := c.Param("name")
for _, user := range users {
if user.Username == name {
c.JSON(http.StatusOK, user)
return
}
}
c.JSON(http.StatusOK, fmt.Errorf("not found user [%s]", name))
})
route.Run()
}
параметры запроса
доступный*gin.Context
Функция Query получает такие параметры, как:/user?name=xcbeyond
.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Username string `json:"username"`
Sex string `json:"sex"`
Age int `json:"age"`
Labels []string `json:"lalels"`
}
func main() {
route := gin.Default()
users := []User{
{
Username: "xcbeyond",
Sex: "男",
Age: 18,
Labels: []string{"年轻", "帅"},
},
}
// 查询参数,如:/user?name=xcbeyond
route.GET("/user", func(c *gin.Context) {
// 获取中的参数
name := c.Query("name")
for _, user := range users {
if user.Username == name {
c.JSON(http.StatusOK, user)
return
}
}
c.JSON(http.StatusOK, "not found user "+name)
})
route.Run()
}
...
пакеты маршрутизации
Gin предоставляет возможность маршрутизировать группы, что удобно для управления маршрутами управления группами, а также классифицировать и обрабатывать те, у которых одинаковый префикс URL-адреса маршрута, что характерно для групп разных версий, например:/api/v1
,/api/v1
.
Кроме того, поддерживается многоуровневая группировка.
package main
import (
"math/rand"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Username string `json:"username"`
Sex string `json:"sex"`
Age int `json:"age"`
Labels []string `json:"lalels"`
}
func main() {
route := gin.Default()
users := []User{
{
Username: "xcbeyond",
Sex: "男",
Age: 18,
Labels: []string{"年轻", "帅"},
},
{
Username: "niki",
Sex: "女",
Age: 16,
Labels: []string{"漂亮"},
},
}
// api分组
api := route.Group("/api")
{
// v1分组
v1 := api.Group("/v1")
{
v1.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
for _, user := range users {
if user.Username == name {
c.JSON(http.StatusOK, user)
return
}
}
c.JSON(http.StatusOK, "not found user :"+name)
})
}
// v2分组
v2 := api.Group("/v2")
{
v2.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
for _, user := range users {
if user.Username == name {
c.JSON(http.StatusOK, user)
return
}
}
// 如果没有查到,则随机返回一个
user := users[rand.Intn(len(users)-1)]
c.JSON(http.StatusOK, "not found user ["+name+"],but user ["+user.Username+"] is exist!")
})
}
}
route.Run()
}
разделение маршрута
В приведенных выше примерах маршрутизации вся информация о маршрутизации записывается в один и тот же исходный файл и функцию, но в реальных проектах будет задействовано большое количество интерфейсов, и писать их вместе слишком неуместно.
В реальных проектах мы предпочитаем разделять код маршрутизации, который можно разделить на отдельные пакеты, несколько исходных файлов маршрутизации и т. д.
В зависимости от масштаба фактического проекта его можно разделить на различные степени детализации.
(Следующие разбивки маршрутизации приведены только для справки и могут быть гибко настроены в соответствии с конкретными проектами!)
Маршруты разбиты на отдельные исходные файлы или пакеты
Выделение реализации маршрутизации в отдельный пакет делает структуру проекта более понятной. Структура проекта следующая:
.
├── main.go
└── routes
└── routes.go
Пример полного исходного кода:route-split-v1
существует/routes/routes.go
Реализовать и зарегистрировать информацию о маршрутизации в файле:
package routes
import (
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Username string `json:"username"`
Sex string `json:"sex"`
Age int `json:"age"`
Labels []string `json:"lalels"`
}
var users []User
// 为方便测试,则直接通过init方式赋值。实际项目中,一般通过数据库等其它方式查询获取数据。
func init() {
users = []User{
{
Username: "xcbeyond",
Sex: "男",
Age: 18,
Labels: []string{"年轻", "帅"},
},
{
Username: "niki",
Sex: "女",
Age: 16,
Labels: []string{"漂亮"},
},
}
}
// SetupRouter 配置路由
func SetupRouter() *gin.Engine {
route := gin.Default()
route.GET("/user/:name", querUserHandler)
// 其它更多路由
return route
}
// handler
func querUserHandler(c *gin.Context) {
name := c.Param("name")
for _, user := range users {
if user.Username == name {
c.JSON(http.StatusOK, user)
return
}
}
c.JSON(http.StatusOK, "not found user :"+name)
}
И вызовите функцию настройки маршрутизации SetupRouter в main.go:
func main() {
route := routes.SetupRouter()
if err := route.Run(); err != nil {
fmt.Printf("startup server failed,err: %v", err)
}
}
Маршрут разбит на несколько исходных файлов
Когда бизнес-функции проекта становятся богатыми, а объем становится больше, все маршруты прописываются в исходный файл route.go, из-за чего исходный файл становится все более и более раздутым, что неудобно для последующего обслуживания и чтения.
Следовательно, его можно разделить на несколько файлов маршрутизации в соответствии с определенным измерением для реализации различных бизнес-функций. Структура проекта следующая:
.
├── main.go
└── routes
├── auth.go
├── routes.go
└── user.go
Пример полного исходного кода:route-split-v2
В пакете маршрутов он разделен на несколько файлов реализации маршрутизации в соответствии с определенным измерением, например: в соответствии с бизнес-модулем его можно разделить на модуль аутентификации (auth.go), пользовательский модуль (user.go) и т. д. ., и в соответствующих файлах маршрутизации. Он реализует определенные бизнес-функции и выполняет регистрацию маршрутизации.
Например, модуль аутентификации auth.go:
package routes
import (
"github.com/gin-gonic/gin"
)
// AuthRegister route register
func AuthRegister(e *gin.Engine) {
e.GET("/auth/login", loginHandler)
e.POST("/auth/logout", logoutUserHanler)
// ……
}
// loginHandler
func loginHandler(c *gin.Context) {
}
// logoutUserHanler
func logoutUserHanler(c *gin.Context) {
}
Среди них определите функцию AuthRegister для регистрации всех маршрутов в модуле.Обратите внимание, что эта функция начинается с заглавной буквы и может быть вызвана main.go вне пакета как глобальная функция.
В route/routes.go настройте маршруты и пропишите маршруты для всех модулей единообразно:
package routes
import (
"github.com/gin-gonic/gin"
)
// SetupRouter 配置路由
func SetupRouter() *gin.Engine {
route := gin.Default()
// other config
// register all route.
UserRegister(route)
AuthRegister(route)
// ……
return route
}
main.go такой же, как и предыдущая версия, как вход для программ и т.д.:
func main() {
route := routes.SetupRouter()
if err := route.Run(); err != nil {
fmt.Printf("startup server failed,err: %v", err)
}
}
Использованная литература: