Web Framework Gin | Маршрутизация Gin

задняя часть Go

​Это 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)
	}
}

Использованная литература:

  1. api-examples
  2. Разделение и регистрация маршрута фреймворка Gin