基本使用

gin是一个高性能的golang web框架,它的代码其实很少,相对于spring来说,搞懂gin真是砍瓜切菜

先来看一下gin的基础用法

import "github.com/gin-gonic/gin"func Init() {r := gin.Default()initRoute(r)r.Run()
}func initRoute(r *gin.Engine) {r.GET("ping", handler)
}func handler(ctx *gin.Context) {ctx.String(200, "Hello World!")
}

这个例子里,我们启动了一个简单的web服务,使用gin.Default创建一个Engine对象,Engine是Gin核心中的核心,我们后面会具体讲解。之后通过initRoute注册一个路由,当访问localhost:8080/ping的时候,就会返回Hello World!。

最后调用r.run让服务启动。只需要很少的几行代码,就能通过gin启动一个web服务。我们主要探索它的实现原理,关于gin更多的语言特性和用法这里就不细说了,更多例子可以前往Gin Examples.

Engine

官网解释:Engine是框架的实例,它包含了复用器、中间件和各类配置。

type Engine struct {// 路由组RouterGroup// 如果设置为true,如果/foo/没有匹配到路由,自动重定向到/fooRedirectTrailingSlash bool// 和RedirectTrailingSlash类似,对path做一些修正RedirectFixedPath boolHandleMethodNotAllowed boolForwardedByClientIP bool// DEPRECATEDAppEngine bool// 是否通过url.RawPath来获取参数UseRawPath bool// If true, the path value will be unescaped.// If UseRawPath is false (by default), the UnescapePathValues effectively is true,// as url.Path gonna be used, which is already unescaped.UnescapePathValues boolRemoveExtraSlash bool// List of headers used to obtain the client IP when// `(*gin.Engine).ForwardedByClientIP` is `true` and// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the// network origins of list defined by `(*gin.Engine).SetTrustedProxies()`.RemoteIPHeaders []string// If set to a constant of value gin.Platform*, trusts the headers set by// that platform, for example to determine the client IPTrustedPlatform string// Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm// method call.MaxMultipartMemory int64delims           render.DelimssecureJSONPrefix stringHTMLRender       render.HTMLRenderFuncMap          template.FuncMapallNoRoute       HandlersChainallNoMethod      HandlersChainnoRoute          HandlersChainnoMethod         HandlersChainpool             sync.Pooltrees            methodTreesmaxParams        uint16maxSections      uint16trustedProxies   []stringtrustedCIDRs     []*net.IPNet
}

Engine里面这么多字段,还有很多方法没往这贴呢,不用着急,我们一点一点的抽丝剥茧,揭开gin的真面目

简单的看,一个gin服务对应一个Engine实例。r = gin.Default()实际上就是创建了一个Engine对象,它的源码也不复杂

func Default() *Engine {engine := New()// 注册中间件engine.Use(Logger(), Recovery())return engine
}func New() *Engine {engine := &Engine{RouterGroup: RouterGroup{Handlers: nil,basePath: "/",root:     true,},FuncMap:                template.FuncMap{},RedirectTrailingSlash:  true,......}engine.RouterGroup.engine = engine// pool存放context对象engine.pool.New = func() interface{} {return engine.allocateContext()}return engine
}

首先New一个Engine出来,初始化一些基础结构,然后通过Use方法注入两个中间件logger和recovery,它们的类型是HandlerFunc,logger打日志用的,recovery用来在服务panic是recover掉,然后返回500,避免服务直接崩溃。

有意思的是engine里面有一个字段pool,类型是sync.pool,在创建Engine的时候,我们也对pool进行了初始化,关于sync.pool可以看我的另一片文章【todo】,可以看到pool的New方法创建并返回了一个context,而context是每一个请求都有的,携带上下文信息的对象,可以想象context是非常重的,如果每一个请求都创建并销毁一个context对象,GC肯定撑不住了啊,还怎么成为一个高性能的wen服务器?所以Gin通过sync.pool来达成对context的复用,优化GC。

路由

不管web服务框架是如何实现的,它最基础的功能就是路由,简单来说就是解析url,然后分派不同的handler来处理对应请求。

在创建Engine后,我们还的告诉它,如何处理路由信息。注册路由非常简单,Engine支持RESTful的6种方法。

func initRoute(r *gin.Engine) {r.GET("ping", pingHandler)
}

实际上Engine是通过继承了RouterGroup(可以在Engine的结构体里找到)来实现路由处理的,所有的路由处理都在RouterGroup中完成,以Get源码为例

func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {return group.handle(http.MethodGet, relativePath, handlers)
}

当我们通过GET注册路由后,会得到一个IRoutes对象,IRoutes本身是一个interface,定义了一系列方法,其中就包含GET,POST…等,不难发现RouterGroup实现了IRoutes。另外注册路由时,对一个path,不只可以穿入一个处理方法,源码里三个点代表我们可以传入多个handler,之后在请求到达时会逐个被调用。而GET直接调用了内部的group.handle,这里面又是如何实现的呢

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

一共有三步

1、计算绝对路径

func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {return joinPaths(group.basePath, relativePath)
}

其实就是字符串join一下,用basePath和当前注册的path组合。哪里来的basePath,以及为什么要join呢?

我们在创建Engine的时候,其实就注册了一个path,它就是"/",其他后续所有注册的path都挂在它下面,如果把它看成一颗树的root节点,在它下面还有更多的子节点,而一个完整的path,就是从根节点到子节点中间经过的所有Path的组合。实际上Gin对于路由的管理就用到了树的结构,这个后面再讲。

2、添加handlers

当前传进去的handlers是path的,但人家basePath也有handlers,basePath是path的前缀,当你发起请求的时候,是不是所有basePath的handlers都应该过一遍呢。添加的过程也并不负责,就是重新开辟一个数组空间,然后把basePath和path的handlers都拷贝到这里,然后返回数组地址。

3、关联绝对路径和handlers

这一步比较重要,逻辑也比较复杂了,先看看最外层的代码,滤去一些无关痛痒的代码

func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {......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)......
}

首先根据method获取根节点,metod有哪些?GET, POST, PUT, DELETE…

如果根节点不存在,就创建一个,然后加入到entine.trees里,entine.trees是methodTrees,methodTrees的定义是[]methodTree,所以entine.trees就是一个methedTree数组。抽丝剥茧,methedTree又是什么玩意儿?

type methodTree struct {method stringroot   *node
}type node struct {path      stringindices   stringwildChild boolnType     nodeTypepriority  uint32children  []*node // child nodes, at most 1 :param style node at the end of the arrayhandlers  HandlersChainfullPath  string
}

链路稍微有点长了,画个图更清晰些

未完待续…

看看Gin框架是如何实现的相关推荐

  1. Gin 框架学习笔记(03)— 输出响应与渲染

    在 Gin 框架中,对 HTTP 请求可以很方便有多种不同形式的响应.比如响应为 JSON . XML 或者是 HTML 等. ​ Context 的以下方法在 Gin 框架中把内容序列化为不同类型写 ...

  2. Gin 框架学习笔记(02)— 参数自动绑定到结构体

    参数绑定模型可以将请求体自动绑定到结构体中,目前支持绑定的请求类型有 JSON .XML .YAML 和标准表单 form数据 foo=bar&boo=baz 等.换句话说,只要定义好结构体, ...

  3. gin框架长连接_gin框架教程一: go框架gin的基本使用

    gin框架教程代码地址: 我们在用http的时候一般都会用一些web框架来进行开发,gin就是这样的一个框架,它有哪些特点呢 一:gin特点 1.性能优秀 2.基于官方的net/http的有限封装 3 ...

  4. go语言学习(二)——Gin 框架简介

    GoWeb开发有很多框架,如Beego.Gin.Revel.Echo.IRis等,学习框架可以快速做开发,对比常见goweb框架,通过其github的活跃度,维护的team,生产环境中的使用率以及师兄 ...

  5. gin框架502错误

    某次gin框架后台服务,请求报502错误.日志提示write timeout,是指服务端在回复客户端时超时了,让程序挂掉,还出现了堆栈打印.其根本原因是,后台处理逻辑耗时超过了上层调用,解决办法是优化 ...

  6. Golang 的Gin框架入门教学

    学习Golang差不多有一个星期时间,开始自己做点小功能,练练手. Gin 介绍 Gin 是一个 Golang 写的 web 框架,具有高性能的优点,,基于 httprouter, 它提供了类似mar ...

  7. windows环境搭建golang的gin框架简易教程

    第一步:安装golang 下载go1.16.7.windows-amd64.msi安装程序,按照界面提示安装 第二步:配置golang代理库地址(此步可忽略) set GOPROXY=https:// ...

  8. go系列之利用Gin框架获取form参数

    利用Gin框架获取form参数 除了通过URL查询参数提交数据到服务器外,常用的还有通过Form表单的方式.Form表单相比URL查询参数,用户体验好,可以承载更多的数据,尤其是文件上传,所以也更为方 ...

  9. gin ajax 获取请求参数,go的gin框架从请求中获取参数的方法

    前言: go语言的gin框架go里面比较好的一个web框架, github的start数超过了18000.可见此框架的可信度 如何获取请求中的参数 假如有这么一个请求: POST   /post/te ...

  10. gin 编译路径错误_[系列] Gin框架 - 自定义错误处理

    概述 很多读者在后台向我要 Gin 框架实战系列的 Demo 源码,在这里再说明一下,源码我都更新到 GitHub 上,地址:https://github.com/xinliangnote/Go 开始 ...

最新文章

  1. [转] asp.net core Introducing View Components
  2. C++ Primer笔记12_运算符重载_递增递减运算符_成员訪问运算符
  3. python3.8爬虫_python爬虫系列(3.8-正则的使用)
  4. mysql 的client_mysql(一)-客户端Client相关
  5. ipmitool 设置网关_Linux下使用命令行配置IPMI
  6. 网络性能测试之pathrate的安装使用
  7. 【每日算法Day 77】LeetCode 第 181 场周赛题解
  8. python装饰器Decorators
  9. Asp.Net WebAPI传递json对象、后台手动接收参数
  10. 读王小波先生的《黄金时代》、《青铜时代》
  11. LaTeX新手半小时速成手册(不速成你打我
  12. golang runtime.Caller 学习笔记
  13. PPT常用快捷键汇总
  14. java pdf转html插件pdf2htmlex
  15. 用ZBrush做游戏建模,3D打印,手办模型、珠宝设计等
  16. 蓝桥杯嵌入式STM32G431——第九届省赛真题电子定时器
  17. 【必看】论文写作入门技巧
  18. 关于直播的技术细节都在这里
  19. 【小睿精选·第八期】为NBA球员提供预警新冠肺炎的智能戒指Oura Ring
  20. 道闸系统服务器功能,道闸系统_停车场自动道闸系统 - 九鼎智能

热门文章

  1. 浙大计算机学院博士生读几年,中国200万在读硕士生和博士生,每月能拿到多少补助?...
  2. 电路中VCC、VDD、VEE和VSS的区别
  3. 爱婴室主要股东再现减持:莫锐伟、王云亦是如此,业绩表现不理想
  4. Config语言与Config.in文件
  5. 网易后端二面经验分享
  6. 小程序:Thu May 05 2022 11:03:00 GMT+0800 (中国标准时间) 渲染层错误
  7. 【荐号】有了它们,成功创业,成就事业巅峰,迎娶白富美,指日可待!
  8. X509V3数字证书介绍
  9. Oracle内存过度消耗风险提醒
  10. 热血传奇技术的一些基础知识