gonic之中间件实现-异常恢复

本文介绍了Gonic框架的中间件实现,特别是异常恢复功能。通过分析源码,展示了如何初始化框架引擎,注册路由及启动监听。在处理HTTP请求时,`context.Next()`确保中间件和业务handler按顺序执行,Recovery中间件能捕获并处理panic,保证服务不中断。
摘要由CSDN通过智能技术生成

最近公司要求更新自研框架,就顺便看了一下gonic的框架实现,代码不多,感觉主要有两个特点,第一个httprouter来实现路由,第二个就是异常恢复,更深入看后原来是中间件,httprouter就不多说了,现记录一下中间件的实现,以便后面需要。

简单的运行一下框架

engine := gin.Default()
engine.GET("/index", foo)
engine.Run(":80")
func foo(ctx *gin.Context)  {
	ctx.String(200, "hello world")
}

主要的一些源码

func Default() *Engine {
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

engine := &Engine{
    RouterGroup: RouterGroup{
        Handlers: nil,
        basePath: "/",
        root:     true,
    },
    FuncMap:                template.FuncMap{},
    RedirectTrailingSlash:  true,
    RedirectFixedPath:      false,
    HandleMethodNotAllowed: false,
    ForwardedByClientIP:    true,
    AppEngine:              defaultAppEngine,
    UseRawPath:             false,
    UnescapePathValues:     true,
    trees:                  make(methodTrees, 0, 9),
    delims:                 render.Delims{"{{", "}}"},
}


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

type methodTrees []methodTree
type methodTree struct {
	method string
	root   *node
}
type node struct {
	path      string
	wildChild bool
	nType     nodeType
	maxParams uint8
	indices   string
	children  []*node
	handlers  HandlersChain
	priority  uint32
}

 

1,代码的一个行,初始化框架引擎,关注里面比较重要的两个字段,routergroup和trees。

routergroup是一个路由组,里面的handlers就是中间件,default函数里面的engine.Use(Logger(), Recovery())就是把logger和recovery注册进这个handlers里面,真正的路由实现是在trees里面,我们知道http method除了常用的get,post还有head等共9种。trees的每个tree就是一个保存了method和使用该method的所有path,源码中的methodtree和node就是实现这个目的,node里面会结构化的保存path信息。

2,代码的第二行,注册路由。里面会把path(index)和handler(foo)注册到engine的trees里面,这里面注册handler的时候会把routergroup的中间件handlers和自定义的handler一起保存。源码如下:

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()
}
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
	finalSize := len(group.Handlers) + len(handlers)
	if finalSize >= int(abortIndex) {
		panic("too many handlers")
	}
	mergedHandlers := make(HandlersChain, finalSize)
	copy(mergedHandlers, group.Handlers)
	copy(mergedHandlers[len(group.Handlers):], handlers)
	return mergedHandlers
}

3.启动框架监听端口。这时候如果有请求进来就会出发engine的ServeHTTP方法。

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


其中的engine.handleHTTPRequest用来处理业务逻辑的。部分源码如下:

 
func (engine *Engine) handleHTTPRequest(context *Context) {
	httpMethod := context.Request.Method
	var path string
	var unescape bool
	if engine.UseRawPath && len(context.Request.URL.RawPath) > 0 {
		path = context.Request.URL.RawPath
		unescape = engine.UnescapePathValues
	} else {
		path = context.Request.URL.Path
		unescape = false
	}

	// 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 {
			root := t[i].root
			// Find route in tree
			handlers, params, tsr := root.getValue(path, context.Params, unescape)
			if handlers != nil {
				context.handlers = handlers
				context.Params = params
				context.Next()
				context.writermem.WriteHeaderNow()
				return
			}
			if httpMethod != "CONNECT" && path != "/" {
				if tsr && engine.RedirectTrailingSlash {
					redirectTrailingSlash(context)
					return
				}
				if engine.RedirectFixedPath && redirectFixedPath(context, root, engine.RedirectFixedPath) {
					return
				}
			}
			break
		}
	}

从源码中可以看到,通过http method找到对应的methoTree里的node,然后根据请求路径path找到对应的handleChain,这个handleChains就是第二部注册的routerGroup.handlers(中间件)+自己的业务handler(foo),
其中的context.Next()会依次执行handlerChans里的handler,该代码会在同一个goroutine里执行,首先执行了中间件,而recovery中间件中有panic的捕获,所以即使自己的业务handler发生了panic也不会中断服务,会被revocer中间件捕获。

阿里云双十一云服务器拼团活动,已经打到最低价99元一年!有需要的可以考虑一波了!

https://m.aliyun.com/act/team1111/#/share?params=N.9g4CZ2TwSh.qilw7y0a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gin-gonic是一个轻量级的Go语言Web框架,它被广泛用于构建高性能的Web应用程序。虽然它被认为是一个相对安全的框架,但没有一个完全免受安全漏洞的框架。下面我将介绍一些可能的gin-gonic gin安全漏洞,并提供相应的解决方案。 1. 跨站脚本攻击(XSS):攻击者通过注入恶意脚本代码来欺骗用户或窃取用户的敏感信息。为了防止XSS攻击,可以使用gin-gonic的SecureJSON中间件来自动转义输出,确保提交的数据不会被解释为HTML标签。 2. 跨站请求伪造(CSRF):攻击者通过伪造合法用户的请求,在用户毫不知情的情况下执行恶意操作。为了防止CSRF攻击,可以在每个表单中添加一个随机生成的令牌,并在请求中进行验证。 3. 敏感数据泄露:在处理敏感信息时,比如用户的密码或信用卡信息,应该尽量避免将其存储为明文。可以使用加密算法对这些敏感数据进行加密存储,并确保存储和传输过程中的数据安全。 4. 不安全的身份认证和授权:如果身份认证和授权不严谨,攻击者可能会绕过这些机制获取非法访问权限。使用合适的身份验证和授权机制,比如JWT(JSON Web Tokens)或OAuth,以确保只有授权用户能够访问受限资源。 5. SQL注入:如果应用程序没有正确过滤或转义用户输入,攻击者可以通过注入恶意SQL语句来执行未经授权的数据库操作。使用参数化查询或ORM(对象关系映射)框架来处理数据库查询,确保用户输入的数据被正确地转义。 总之,虽然gin-gonic gin是一个相对安全的框架,但在开发过程中仍然需要注意潜在的安全漏洞,并采取适当的措施来预防和修复这些漏洞。同时,及时更新和维护框架版本也是保证安全性的重要一环。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值