Go Lesson 03: Интерпретация простой демонстрации Gin

Gin

图片

I. Обзор

1. Введение
  • Для поддержки веб-разработки Go официально предоставляетnet/httpToolkit, но в реальных проектах команда все равно выберет более эффективный и удобный веб-фреймворк, напримерGin,Echo,BeegoЖдать;
  • Среди этих команд многие команды выбралиGinэта структура, она находится вnet/httpОптимизирован на основе; по сравнению с другими основными фреймворками, онлучшая производительностьа такжеболее быстрая маршрутизация;
2. Преимущества джина
  • быстро: на основеRadixПроизводительность маршрутизации по дереву очень высока.

  • Поддержка промежуточного программного обеспечения: существует множество встроенных промежуточного программного обеспечения, таких какLogger,Gzip,AuthorizationЖдать.

  • Восстановление после сбоя: сбой программы, вызванный паникой, может быть обнаружен, чтобы веб-служба всегда могла работать.

  • Проверка JSON: можно проверить запросJSONФормат данных.

  • Группировка маршрутизации: поддерживает группировку маршрутизации (RouteGroup), что упрощает организацию маршрутов.

  • Механизм управления ошибками: может собирать ошибки в программе

  • Несколько методов рендеринга данных: поддержкаHTML,JSON,YAML,XMLи другие ответы формата данных.

  • Расширяемость: промежуточное ПО очень легко расширяется.

  • Средство проверки данных: средство проверки данных поддерживается и может быть настроено.

3. Простая демонстрация джина
package main

import (
	"github.com/gin-gonic/gin"
    "net/http"
)

func setupRouter() *gin.Engine {

	r := gin.Default()
	// Ping test
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status" : 0,
			"msg" 	 : "success",
			"data"   :  gin.H {
				"content" : "pong",
			},
		})
	})
	return r
}

func main() {
   r := setupRouter()
   r.Run() 
}

2. Интерпретация демо-версии Gin Simple

Как видно из демо-кода, опыт использования Gin очень гладкий.Есть четыре шага для определения и обработки веб-запросов:импортный пакет,определить маршруты,обработчик записи,порт прослушивания.

1. Импортируйте пакет
import "github.com/gin-gonic/gin"
2. Определите маршрут
  • gin.engine - это двигатель маршрутизации, обычно используетсяgin.Default()метод создает и возвращаетgin.Engine实例.
r := gin.Default() //r默认使用了Logger和Recovery两个中间件

иллюстрировать:Можно использоватьgin.New()метод создает и возвращаетgin.Engine实例

3. Написать обработчик

С маршрутом по умолчанию мы можем создавать методы для обработки HTTP-запросов, используя метод GET в примере:

// Ping test
r.GET("/ping", func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
			"status" : 0,
			"msg" 	 : "success",
			"data"   :  gin.H {
				"content" : "pong",
		},
	})
})
  • Базовая реализация метода Get заключается в вызовеRouterGroupизhandleметод, обработка запроса выполняется с использованиемHandlerFuncМетод типа
// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
	return group.handle("GET", relativePath, handlers)
}

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)
  • Описание: Gin поддерживает все распространенные методы HTTP-запросов, такие какGET,POST,PUT,PATCH,OPTIONS,HEAD,DELETE.
4. Порт прослушивания
  • После определения запроса используйте метод Run() для прослушивания порта и начала приема HTTP-запросов.Если метод Run() не передает параметры, он по умолчанию будет прослушивать порт 8080.
r.Run() 
  • Ключ к базовой реализации метода Run:http.ListenAndServe, где: http отnet/httpМешок.
func (engine *Engine) Run(addr ...string) (err error) {
	defer func() { debugPrintError(err) }()

	address := resolveAddress(addr)
	debugPrint("Listening and serving HTTP on %s\n", address)
	//
	err = http.ListenAndServe(address, engine)
	return
}

3. Важные структуры данных в Gin

В простом демонстрационном коде Gin мы обнаружили три важные структуры данных Go:gin.Engine,gin.Contextа такжеgin.RouterGroup

1. Джин.Двигатель
  • gin.Engine — это точка входа в структуру; мы используем объект Engine для определения информации о маршрутизации службы, сборки подключаемых модулей и запуска служб, и весь веб-сервис управляется им.
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
type Engine struct {
	RouterGroup
	
	//....
}
  • gin.Engine по сути представляет собой оболочку встроенного HTTP-сервера, что делает его более удобным в использовании.
  • Функция gin.Default () создаст объект Engine по умолчанию, который содержит два общих плагина по умолчанию, а именно Logger и Recovery. Logger используется для вывода журналов запросов. Recovery гарантирует, что при панике одного запроса журнал стека исключений записывается и вывод унифицированного ответа на ошибку (推荐使用).
func Default() *Engine {
   debugPrintWARNINGDefault()
   engine := New()
   engine.Use(Logger(), Recovery())
   return engine
}
  • Функция gin.New() создаст объект Engine по умолчанию, который не содержит экземпляров промежуточного программного обеспечения gin.Engine.
2. Джин.Контекст
  • Информационный объект контекста запроса, который является входным параметром всех обработчиков запросов.gin.ContextСтруктура определяется следующим образом:
// Context允许我们在中间件之间传递变量,管理流程,验证请求的JSON,并返回JSON
type Context struct {
	//请求对象
	Request   *http.Request
    
    // 用来响应 
    writermem responseWriter
	Writer    ResponseWriter
 	// URL里面的参数,比如:/xx/:id  
	Params   Params
	
     // 参与的处理者(中间件 + 请求处理者列表)
    handlers HandlersChain
    // 当前处理到的handler的下标
    index    int8

	fullPath string
	
    // Engine单例
	engine *Engine

	// 在context可以设置的值
	Keys map[string]interface{}

	// 一系列的错误
	Errors errorMsgs

	//为内容协商定义一组手动接受的格式。
	Accepted []string

	// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
	queryCache url.Values

	// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
	// or PUT body parameters.
	formCache url.Values
}
  • Объект контекста Context не генерируется каждый раз, а вынимается из пула объектов, а реальное ядро ​​обработки запроса находится вhandleHTTPRequestв функции.
  • Основная логика в функции handleHTTPRequest: в соответствии с методом запроса и запрошенным URI найти и вызвать обработанныймассив функций(Включая функцию обработки, которую мы определены, а также функция обработки среднего слоя).
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {

	// 从对象池中获取一个context对象
	c := engine.pool.Get().(*Context)

	// 初始化上下文对象,因为从对象池取出来的数据,有脏数据,故要初始化。
	c.writermem.reset(w)
	c.Request = req
	c.reset()

    //处理web请求 (http请求处理)
	engine.handleHTTPRequest(c)

	//将Context对象扔回对象池了
	engine.pool.Put(c)
}
3. джин.Группа маршрутизаторов
  • RouterGroup — это группа маршрутизации, представляющая собой упаковку дерева маршрутизации, и все правила маршрутизации в конечном итоге управляются ею. Структура Engine наследует RouterGroup, поэтому Engine напрямую имеет все функции управления маршрутизацией от RouterGroup.
// RouterGroup is used internally to configure router, a RouterGroup is associated with
// a prefix and an array of handlers (middleware).
type RouterGroup struct {
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}

// HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc
  • Объект RouteGroup в основном включает в себя:basePath(префиксный путь),Engine 指针а такжеHandlers(массив функций обработки).

  • RouterGroup реализует ряд методов маршрутизации, определенных интерфейсом IRouter; эти методы в конечном итоге подключают обработчик запросов к дереву маршрутизации, вызывая метод Engine.addRoute.

  • Внутри RouterGroup есть атрибут пути префикса, который добавит этот префикс ко всем подпутям и поместит их в дерево маршрутизации. С помощью этого пути префикса может быть реализована функция группировки URL-адресов. Префикс пути объекта RouterGroup, встроенного в объект Engine, — это /, который представляет корневой путь. RouterGroup поддерживает вложенность групп.Используя метод Group, группу можно связать ниже группы.

    v1 := r.Group("/api/v1")
    {
    	v1.POST("/submit",submit)
    	v1.GET("/list",list)
    }
    // Engine对象中RouterGroup对象是第一层分组(根分组),v1是根分组的子分组。
    
4. джин.ч
  • gin.H — это сокращенное имя для map[string]interface{}.
type H map[string]interface{}