分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > IT知识

go web framework gin 路由表的设计

发布时间:2023-09-06 02:29责任编辑:林大明关键词:暂无标签

在上一篇go web framework gin 启动流程分析这一篇文章中,我分析了go gin启动的过程,在这一篇文章中我将继续上面的分析,讨论gin 中路由表是如何设计的?

首先查看engine.handleHTTPRequest() 这个方法的定义:

func (engine *Engine) handleHTTPRequest(c *Context) {httpMethod := c.Request.Method //获取Request methodpath := c.Request.URL.Path //获取 Request URL Pathunescape := falseif engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {path = c.Request.URL.RawPathunescape = engine.UnescapePathValues}// Find root of the tree for the given HTTP methodt := engine.treesfor i, tl := 0, len(t); i < tl; i++ { //遍历每一个methord treeif t[i].method != httpMethod {continue}root := t[i].root// Find route in treehandlers, params, tsr := root.getValue(path, c.Params, unescape) //如果找到这个method tree, 那么就从这个tree中根据path,params, unescape 找到对应的handlersif handlers != nil { //执行handlerc.handlers = handlersc.Params = paramsc.Next()c.writermem.WriteHeaderNow()return} ???????????????//异常处理部分if httpMethod != "CONNECT" && path != "/" {if tsr && engine.RedirectTrailingSlash {redirectTrailingSlash(c)return}if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {return}}break} ???????//处理不能响应的methodif engine.HandleMethodNotAllowed {for _, tree := range engine.trees {if tree.method == httpMethod {continue}if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {c.handlers = engine.allNoMethodserveError(c, http.StatusMethodNotAllowed, default405Body)return}}}c.handlers = engine.allNoRouteserveError(c, http.StatusNotFound, default404Body)}

 抛开其它的部分不看,只看如何根据path, nil, unescape 获取到handlers.

// getValue returns the handle registered with the given path (key). The values of// wildcards are saved to a map.// If no handle can be found, a TSR (trailing slash redirect) recommendation is// made if a handle exists with an extra (without the) trailing slash for the// given path.func (n *node) getValue(path string, po Params, unescape bool) (handlers HandlersChain, p Params, tsr bool) {p = powalk: // Outer loop for walking the treefor {if len(path) > len(n.path) {if path[:len(n.path)] == n.path {path = path[len(n.path):]// If this node does not have a wildcard (param or catchAll)// child, ?we can just look up the next child node and continue// to walk down the treeif !n.wildChild {c := path[0]for i := 0; i < len(n.indices); i++ {if c == n.indices[i] {n = n.children[i]continue walk}}// Nothing found.// We can recommend to redirect to the same URL without a// trailing slash if a leaf exists for that path.tsr = path == "/" && n.handlers != nilreturn}// handle wildcard childn = n.children[0]switch n.nType {case param:// find param end (either ‘/‘ or path end)end := 0for end < len(path) && path[end] != ‘/‘ {end++}// save param valueif cap(p) < int(n.maxParams) {p = make(Params, 0, n.maxParams)}i := len(p)p = p[:i+1] // expand slice within preallocated capacityp[i].Key = n.path[1:]val := path[:end]if unescape {var err errorif p[i].Value, err = url.QueryUnescape(val); err != nil {p[i].Value = val // fallback, in case of error}} else {p[i].Value = val}// we need to go deeper!if end < len(path) {if len(n.children) > 0 {path = path[end:]n = n.children[0]continue walk}// ... but we can‘ttsr = len(path) == end+1return}if handlers = n.handlers; handlers != nil {return}if len(n.children) == 1 {// No handle found. Check if a handle for this path + a// trailing slash exists for TSR recommendationn = n.children[0]tsr = n.path == "/" && n.handlers != nil}returncase catchAll:// save param valueif cap(p) < int(n.maxParams) {p = make(Params, 0, n.maxParams)}i := len(p)p = p[:i+1] // expand slice within preallocated capacityp[i].Key = n.path[2:]if unescape {var err errorif p[i].Value, err = url.QueryUnescape(path); err != nil {p[i].Value = path // fallback, in case of error}} else {p[i].Value = path}handlers = n.handlersreturndefault:panic("invalid node type")}}} else if path == n.path {// We should have reached the node containing the handle.// Check if this node has a handle registered.if handlers = n.handlers; handlers != nil {return}if path == "/" && n.wildChild && n.nType != root {tsr = truereturn}// No handle found. Check if a handle for this path + a// trailing slash exists for trailing slash recommendationfor i := 0; i < len(n.indices); i++ {if n.indices[i] == ‘/‘ {n = n.children[i]tsr = (len(n.path) == 1 && n.handlers != nil) ||(n.nType == catchAll && n.children[0].handlers != nil)return}}return}// Nothing found. We can recommend to redirect to the same URL with an// extra trailing slash if a leaf exists for that pathtsr = (path == "/") ||(len(n.path) == len(path)+1 && n.path[len(path)] == ‘/‘ &&path == n.path[:len(n.path)-1] && n.handlers != nil)return}}

 实际上这部分的实现以及insertChild 和 addRoute部分都是基于基树(Radix tree)实现的。关于基树的知识,参考:待研究的那些经典算法

go web framework gin 路由表的设计

原文地址:https://www.cnblogs.com/Spider-spiders/p/10233892.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved