golang学习之go web开发Gin框架

gin是用go语言编写的一个http web框架
官方网站:https://gin-gonic.com/zh-cn/

一、gin 安装

$ go get github.com/gin-gonic/gin

二、Hello World

1、代码

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": "pong",
		})
	})
	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

2、运行

go run main.go

运行main.go打印日志:

[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /ping                     --> main.main.func1 (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080

3、访问

浏览器访问 http://localhost:8080/ping 响应如下:

{
    
    "message":"pong"}

三、源码分析

1、r := gin.Default()

1、跟进 gin.Default()

// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
    
    
	// 此处可以看到程序启动时打印的日志:[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
	debugPrintWARNINGDefault()
	// 初始化引擎
	engine := New()
	// 使用默认日志打印及异常处理组件
	engine.Use(Logger(), Recovery())
	return engine
}

2、跟进 engine := New()

func New() *Engine {
    
    
	// 此处可以看到程序启动时打印的日志
	// [WARNING] Running in "debug" mode. Switch to "release" mode in production.
	// using env:	export GIN_MODE=release
	// using code:	gin.SetMode(gin.ReleaseMode)
	debugPrintWARNINGNew()
	// 初始化引擎
	engine := &Engine{
    
    
		// 路由组
		RouterGroup: RouterGroup{
    
    
			Handlers: nil,
			basePath: "/",
			root:     true,
		},
		FuncMap:                template.FuncMap{
    
    },
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      false,
		HandleMethodNotAllowed: false,
		ForwardedByClientIP:    true,
		RemoteIPHeaders:        []string{
    
    "X-Forwarded-For", "X-Real-IP"},
		TrustedPlatform:        defaultPlatform,
		UseRawPath:             false,
		RemoveExtraSlash:       false,
		UnescapePathValues:     true,
		MaxMultipartMemory:     defaultMultipartMemory,
		trees:                  make(methodTrees, 0, 9),
		delims:                 render.Delims{
    
    Left: "{
    
    {", Right: "}}"},
		secureJSONPrefix:       "while(1);",
		trustedProxies:         []string{
    
    "0.0.0.0/0", "::/0"},
		trustedCIDRs:           defaultTrustedCIDRs,
	}
	// 设置路由组引擎为本引擎
	engine.RouterGroup.engine = engine
	engine.pool.New = func() any {
    
    
		return engine.allocateContext()
	}
	return engine
}

3、路由组定义:

type RouterGroup struct {
    
    
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}

2、r.GET()

1、跟进 r.GET(“/ping”, func(c *gin.Context),可以看到GET()方法的接收器是group *RouterGroup

// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
    
    
	return group.handle(http.MethodGet, relativePath, handlers)
}

2、跟进 group.handle(http.MethodGet, relativePath, handlers)

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()
}

3、跟进group.engine.addRoute(httpMethod, absolutePath, handlers)

func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
    
    
	assert1(path[0] == '/', "path must begin with '/'")
	assert1(method != "", "HTTP method can not be empty")
	assert1(len(handlers) > 0, "there must be at least one handler")
	debugPrintRoute(method, path, handlers)
	// 获取请求http请求方法root
	root := engine.trees.get(method)
	if root == nil {
    
    
		root = new(node)
		root.fullPath = "/"
		engine.trees = append(engine.trees, methodTree{
    
    method: method, root: root})
	}
	// 绑定路由及请求处理器函数
	root.addRoute(path, handlers)
	// Update maxParams
	if paramsCount := countParams(path); paramsCount > engine.maxParams {
    
    
		engine.maxParams = paramsCount
	}
	if sectionsCount := countSections(path); sectionsCount > engine.maxSections {
    
    
		engine.maxSections = sectionsCount
	}
}

3、r.Run()

1、跟进r.Run()

// Run attaches the router to a http.Server and starts listening and serving HTTP requests.
// It is a shortcut for http.ListenAndServe(addr, router)
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func (engine *Engine) Run(addr ...string) (err error) {
    
    
	defer func() {
    
     debugPrintError(err) }()
	if engine.isUnsafeTrustedProxies() {
    
    
		// 此处可以看到程序启动时打印的日志:
		debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
			"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
	}
	// 此处可以看到程序启动时打印的日志: Environment variable PORT is undefined. Using port :8080 by default
	address := resolveAddress(addr)
	debugPrint("Listening and serving HTTP on %s\n", address)
	// 此处为go语言的ListenAndServe
	err = http.ListenAndServe(address, engine.Handler())
	return
}

2、跟进engine.Handler(),可以看到请求处理器就是 Engine

func (engine *Engine) Handler() http.Handler {
    
    
	if !engine.UseH2C {
    
    
		return engine
	}
	h2s := &http2.Server{
    
    }
	return h2c.NewHandler(engine, h2s)
}

3、既然请求处理器是 Engine,那么 Engine就实现了ServeHTTP(w http.ResponseWriter, req *http.Request) ,跟踪代码可以看到其实现方式:

// ServeHTTP conforms to the http.Handler interface.
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)
	engine.pool.Put(c)
}

4、跟进engine.handleHTTPRequest(c ),已删除部分代码

func (engine *Engine) handleHTTPRequest(c *Context) {
    
    
	t := engine.trees
	for i, tl := 0, len(t); i < tl; i++ {
    
    
		if t[i].method != httpMethod {
    
    
			continue
		}
		root := t[i].root
		// 根据请求路由找到GET函数注册的请求处理器函数
		// Find route in tree
		value := root.getValue(rPath, c.params, c.skippedNodes, 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
		}
}

5、跟进c.Next()可以看到 Hello World 中GET绑定的请求处理器函数的执行

func (c *Context) Next() {
    
    
	c.index++
	for c.index < int8(len(c.handlers)) {
    
    
		// 执行Hello World 中GET绑定的请求处理器函数
		c.handlers[c.index](c)
		c.index++
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_56349119/article/details/126566284