джин фреймиметь дело с Запросить записьфункцияServeHTTP
:
// gin.go
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Здесь используется пул объектов
c := engine.pool.Get().(*Context)
// Инициализировать после получения объекта
c.writermem.reset(w)
c.Request = req
c.reset()
engine.handleHTTPRequest(c) // иметь дело Функция HTTP-запроса
engine.pool.Put(c) // иметь дело с После выполнения запроса вернуть объект в пул
}
Обработка handleHTTPRequest
func (engine *Engine) handleHTTPRequest(c *Context) {
httpMethod := c.Request.Method
rPath := c.Request.URL.Path
unescape := false
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
rPath = c.Request.URL.RawPath
unescape = engine.UnescapePathValues
}
if engine.RemoveExtraSlash {
rPath = cleanPath(rPath)
}
// Find root of the tree for the given HTTP method
// Найдите соответствующее дерево маршрутизации на основе метода запроса.
t := engine.trees
for i, tl := 0, len(t); i < tl; i++ {
if t[i].method != httpMethod {
continue
}
root := t[i].root
// Find route in tree Поиск по пути в дереве маршрутизации
value := root.getValue(rPath, c.params, unescape)
if value.params != nil {
c.Params = *value.params
}
if value.handlers != nil {
// Обновите свойства объекта контекста и передайте несколько адресов функций маршрутизации, управляемых управлением контекста.
c.handlers = value.handlers
c.fullPath = value.fullPath
// Выполните цепочку функций рекурсивно. Далее здесь особенно интересно
c.Next()
c.writermem.WriteHeaderNow()
return
}
if httpMethod != "CONNECT" && rPath != "/" {
if value.tsr && engine.RedirectTrailingSlash {
redirectTrailingSlash(c)
return
}
if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
return
}
}
break
}
if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees {
if tree.method == httpMethod {
continue
}
if value := tree.root.getValue(rPath, nil, unescape); value.handlers != nil {
c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body)
return
}
}
}
c.handlers = engine.allNoRoute
serveError(c, http.StatusNotFound, default404Body)
}
основной код
// По пути и параметрам запроса найдите соответствующий маршрутизацияиметь дело сфункция
value := root.getValue(rPath, c.Params, unescape)
// Рекурсивно выполнять связанные методы обработчика
c.Next()
c.Next(), суть этого метода в основном заключается в облегчении доступа к промежуточному программному обеспечению (Middleware), чтобы код мог работать модульным образом.
Взгляните на конкретную реализацию Next
func (c *Context) Next() {
c.index++
for c.index < int8(len(c.handlers)) {
// Казнь связана с промежуточным программное метод обеспечения или действительныймаршрутизацияиметь дело сфункция
c.handlers[c.index](c)
c.index++
}
}
Следующий дизайн здесь очень интересен. Вот пример, который я привел
package main
import "fmt"
// модель лука
type Context struct {
handles []func(c *Context)
index int8 // Представляет индекс функции выше
}
func (this *Context) Use(f func(c *Context)) {
this.handles = append(this.handles, f)
}
func (this *Context) Get(path string, f func(c *Context)) {
this.handles = append(this.handles, f)
}
func (this *Context) Next() {
this.index++
this.handles[this.index](this)
}
func (this *Context) Run() {
this.handles[0](this) // Выполните первую функцию
}
func Middleware1() func(c *Context) {
return func(c *Context) {
fmt.Println("middleware start")
c.Next()
fmt.Println("middleware end")
}
}
func Middleware2() func(c *Context) {
return func(c *Context) {
fmt.Println("middleware2 start")
c.Next()
fmt.Println("middleware2 end")
}
}
func main() {
c := &Context{}
c.Use(Middleware1())
c.Use(Middleware2())
c.Get("/", func(c *Context) {
fmt.Println("Get handle func ")
},
)
c.Run()
}
Его призвание Реализован псевдокод метода Next для углубления понимания:
Функции обработки имеют отношение последовательного выполнения, и функция обработки может вернуться раньше, вызвав метод Abort без рекурсивного вызова фактической функции обработки. Это промежуточное программное обеспечение может легко позволить нашему бизнес-коду получить доступ к проверке разрешений, аутентификации, управлению журналами и другим функциональным модулям.
сопоставление Маршруты состоят из узлов getValue
реализован методом。getValue
по заданному пути(ключ)возвращатьсяnodeValue
ценить,Сохранить зарегистрированный иметь дело сфункция и данные параметра сопоставленного пути.
джин-фреймворк предполагает промежуточное программное обеспечение Связанные4широко используемый метод,Они естьc.Next()
、c.Abort()
、c.Set()
、c.Get()
。
Регистрация промежуточного программного обеспечения
промежуточное в рамке от джина программное обеспечение Дизайн очень умный,из наиболее часто используемыхr := gin.Default()
изDefault
функция Начать просмотр,它内部构造一个新изengine
тогда пройдиUse()
функция ЗарегистрированLogger
промежуточное программное обеспечениеиRecovery
промежуточное программное обеспечение:
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery()) // Два промежуточных зарегистрированы по умолчанию программное обеспечение
return engine
}
Использовать() функцию
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...) // Фактически вызывается Useфункция RouterGroup.
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}
зарегистрироватьсяпромежуточное программное обеспечение Фактически, это будетпромежуточное программное обеспечениефункциядобавить кgroup.Handlers
середина:
// Use adds middleware to the group, see example code in GitHub.
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
group.Handlers = append(group.Handlers, middleware...)
return group.returnObj()
}
Когда мы регистрируем маршрут, мы объединим соответствующую функцию маршрута с предыдущей функцией промежуточного программного обеспечения:
func (group *RouterGroup) handle(httpMethod, relativePath string,handlers HandlersChain) IRoutes {
absolutePath := group.calculateAbsolutePath(relativePath)
handlers = group.combineHandlers(handlers) // Воляиметь дело с请求изфункцияипромежуточное программное обеспечениефункция结合
group.engine.addRoute(httpMethod, absolutePath, handlers)
return group.returnObj()
}
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "success",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
Фактически, промежуточное программное обеспечение gin на самом деле представляет собой HandlerFunc, определенный Gin. Давайте сначала посмотрим на r.Run()
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
}
Gin предоставляет промежуточное программное обеспечение gin.BasicAuth для создания базовой аутентификации.
r := gin.Default()
r.Use(gin.BasicAuth(gin.Accounts{
"admin": "123456",
}))
Например, при доступе требуются имя пользователя и пароль.
Вы также можете аутентифицировать определенные URL-адреса, например:
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, «первая страница»)
})
adminGroup := r.Group("/admin")
adminGroup.Use(gin.BasicAuth(gin.Accounts{
"admin": "123456",
}))
}