【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析
目录【阅读时间:约10分钟】
- 一.概述
- 二.对比: gorilla/mux与net/http DefaultServeMux
- 三.简单使用
- 四.源码简析
- 1.NewRouter函数
- 2.HandleFunc函数
- 设置路由的HTTP方法
- 设置路由的域名
- 限制HTTP 方案
- 设置路径前缀和子路由
- 3.PathPrefix函数
- 五.References
一.概述
gorilla/mux程序包,是一个强大的url路由和调度器,它具有小巧但是稳定高效的特性。
不仅可以支持正则路由,还可以按照Method、header、host等信息匹配,可以从我们设定的路由表达式中提取出参数方便上层应用,而且完全兼容http.ServerMux。
二.对比: gorilla/mux与net/http DefaultServeMux
Go 官方标准库 net/http
自带的 DefaultServeMux
底层实现,通过 DefaultServeMux
提供的路由处理器虽然简单易上手,但是存在很多不足,比如:
- 不支持参数设定,例如
/user/:uid
这种泛类型匹配; - 对 REST 风格接口支持不友好,无法限制访问路由的方法;
- 对于拥有很多路由规则的应用,编写大量路由规则非常繁琐。
为此,我们可以使用第三方库 gorilla/mux
提供的更加强大的路由处理器(mux
代表 HTTP request multiplexer
,即 HTTP 请求多路复用器),和 http.ServeMux
实现原理一样,gorilla/mux
提供的路由器实现类 mux.Router
也会匹配用户请求与系统注册的路由规则,然后将用户请求转发过去。
mux.Router
主要具备以下特性:
- 实现了
http.Handler
接口,所以和http.ServeMux
完全兼容; - 可以基于 URL 主机、路径、前缀、scheme、请求头、请求参数、请求方法进行路由匹配;
- URL 主机、路径、查询字符串支持可选的正则匹配;
- 支持构建或反转已注册的 URL 主机,以便维护对资源的引用;
- 支持路由嵌套(类似 Laravel 中的路由分组),以便不同路由可以共享通用条件,比如主机、路径前缀等。
三.简单使用
安装程序包:
go get -u github.com/gorilla/mux
样例①:
基于Golang的简单web服务程序开发——CloudGo
主要的相关函数为NewServer函数与initRoutes函数:
// NewServer configures and returns a Server.
func NewServer() *negroni.Negroni {formatter := render.New(render.Options{Directory: "templates",Extensions: []string{".html"},IndentJSON: true,})n := negroni.Classic()mx := mux.NewRouter()initRoutes(mx, formatter)n.UseHandler(mx)return n
}func initRoutes(mx *mux.Router, formatter *render.Render) {webRoot := os.Getenv("WEBROOT")if len(webRoot) == 0 {if root, err := os.Getwd(); err != nil {panic("Could not retrive working directory")} else {webRoot = root//fmt.Println(root)}}mx.HandleFunc("/api/test", apiTestHandler(formatter)).Methods("GET")mx.HandleFunc("/", homeHandler(formatter)).Methods("GET")mx.HandleFunc("/user", userHandler).Methods("POST")mx.PathPrefix("/").Handler(http.FileServer(http.Dir(webRoot + "/assets/")))
}
样例②:
package mainimport ("fmt""github.com/gorilla/mux""log""net/http"
)func sayHelloWorld(w http.ResponseWriter, r *http.Request) {w.WriteHeader(http.StatusOK) // 设置响应状态码为 200fmt.Fprintf(w, "Hello, World!") // 发送响应到客户端
}func main() {r := mux.NewRouter()r.HandleFunc("/hello", sayHelloWorld)log.Fatal(http.ListenAndServe(":8080", r))
}
在 main
函数中的第一行显式初始化了 mux.Router
作为路由器,然后在这个路由器中注册路由规则,最后将这个路由器传入 http.ListenAndServe
方法,整个调用过程和之前并无二致,因为我们前面说了,mux.Router
也实现了 Handler
接口。
运行这段代码,在浏览器访问 http://localhost:8080/hello
,即可渲染出如下结果:
Hello, World!
四.源码简析
gorilla/mux源码可分为context、mux、regex、route四个部分,在CloudGo项目开发过程中,我主要使用了NewRouter、HandleFunc和PathPrefix这三个函数。下面对这三个函数进行分析:
1.NewRouter函数
Router是一个结构体,如下:
type Router struct {// Configurable Handler to be used when no route matches.NotFoundHandler http.Handler// Configurable Handler to be used when the request method does not match the route.MethodNotAllowedHandler http.Handler// Parent route, if this is a subrouter.parent parentRoute// Routes to be matched, in order.routes []*Route// Routes by name for URL building.namedRoutes map[string]*Route// See Router.StrictSlash(). This defines the flag for new routes.strictSlash bool// See Router.SkipClean(). This defines the flag for new routes.skipClean bool// If true, do not clear the request context after handling the request.// This has no effect when go1.7+ is used, since the context is stored// on the request itself.KeepContext bool// see Router.UseEncodedPath(). This defines a flag for all routes.useEncodedPath bool
}
调用NewRouter函数可用来实例化一个Router:
// NewRouter returns a new router instance.
func NewRouter() *Router {return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}
这里可以看见,它开辟了一个装Route指针的map,然后默认该Router的KeepContext
为false
,意思是在请求被处理完之后清除该请求的上下文。
2.HandleFunc函数
// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,*http.Request)) *Route {return r.NewRoute().Path(path).HandlerFunc(f)
}
若只观察HandleFunc函数,会发现其代码只有几行,其主要功能是使用URL的匹配器注册新路由。
gorilla/mux的HandleFunc函数功能很强大,主要有以下功能:
设置路由的HTTP方法
限制路由处理器只处理指定的HTTP
方法的请求:
router.HandleFunc("/books/{title}", CreateBook).Methods("POST")
router.HandleFunc("/books/{title}", ReadBook).Methods("GET")
router.HandleFunc("/books/{title}", UpdateBook).Methods("PUT")
router.HandleFunc("/books/{title}", DeleteBook).Methods("DELETE")
上面的就是一组可以响应具体HTTP
方法的RESTful
风格的接口的路由。
设置路由的域名
限制路由处理器只处理访问指定域名加路由的请求:
router.HandleFunc("/books/{title}", BookHandler).Host("www.mybookstore.com")
限制HTTP 方案
将请求处理程序可响应的HTTP
方案限制为http
或者https
。
router.HandleFunc("/secure", SecureHandler).Schemes("https")
router.HandleFunc("/insecure", InsecureHandler).Schemes("http")
设置路径前缀和子路由
bookrouter := router.PathPrefix("/books").Subrouter()
bookrouter.HandleFunc("/", AllBooks)
bookrouter.HandleFunc("/{title}", GetBook)
3.PathPrefix函数
// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {return r.NewRoute().PathPrefix(tpl)
}
PathPrefix函数源码也只有几行,它的功能只是简单地增加URL的前缀,通常结合HandleFunc函数和Handler函数来使用。
五.References
- 基于 gorilla/mux 包实现路由定义和请求分发:基本使用
- gorilla/mux类库解析
- Gorilla源码分析之gorilla/mux源码分析
- 从一个例子分析gorilla/mux源码
- gorilla/mux官方GitHub
【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析相关推荐
- Flume 1.7 源码分析(三)程序入口
Flume 1.7 源码分析(一)源码编译 Flume 1.7 源码分析(二)整体架构 Flume 1.7 源码分析(三)程序入口 Flume 1.7 源码分析(四)从Source写数据到Channe ...
- Netty源码分析系列之常用解码器(下)——LengthFieldBasedFrameDecoder
扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 前言 在上一篇文章中分析了三个比较简单的解码器,今天接着分析最后一个常用的解码器:Leng ...
- v56.05 鸿蒙内核源码分析(进程映像) | 程序是如何被加载运行的 | 百篇博客分析OpenHarmony源码
子畏于匡,颜渊后.子曰:"吾以女为死矣."曰:"子在,回何敢死?" <论语>:先进篇 百篇博客系列篇.本篇为: v56.xx 鸿蒙内核源码分析(进程 ...
- 【SA8295P 源码分析】02 - SA8295P 整包镜像分析
[SA8295P 源码分析]02 - SA8295P 整包镜像分析 一.UFS LUNs 二.开机启动相关镜像介绍 三.QNX Host相关镜像介绍 四.Android GVM 相关镜像介绍 五.其他 ...
- 【SA8295P 源码分析】16 - TouchScreen Panel (TP)线程函数 tp_recv_thread() 源码分析
[SA8295P 源码分析]16 - TouchScreen Panel (TP)线程函数 tp_recv_thread 源码分析 一.TP 线程函数:tp_recv_thread() 二.处理&am ...
- 【SA8295P 源码分析】22 - QNX Ethernet MAC 驱动 之 emac_entry / emac_attach 函数源码分析
[SA8295P 源码分析]22 - QNX Ethernet MAC 驱动 之 emac_entry / emac_attach 函数源码分析 一.EMAC:libdevnp-emac-eth.so ...
- 基于Golang的监听读取配置文件的程序包开发——simpleConfig_v1
基于Golang的监听&读取配置文件的程序包开发--simpleConfig_v1 [阅读时间:约10分钟] 一.配置文件概述 二.系统环境&项目介绍 1.系统环境 2.项目的任务要求 ...
- 【源码分析】微信小程序 - 01表单组件 - 01button - 实践
前言:此系列,结合Demo的源码,做一些实践和讨论: 1 Demo的效果: 微信小程序给出的button的Demo效果如上: 2 源码分析: 2.1 button.js js文件里面,定义了一些变量和 ...
- [授权发表]源码分析:静态分析 C 程序函数调用关系
故事缘由 工欲善其事,必先利其器.今天我们来玩转一个小工具,叫 Callgraph,它可以把 C 语言的函数调用树(或者说流程图)画出来. 传统的命令行工具 Cscope,Ctags 可以结合vim ...
最新文章
- 用C++的random_shuffle()函数打乱int数组顺序
- clouderamanager-server启动,log日志中说需要mysql驱动的解决办法
- 各种编程语言的深度学习库整理
- 图解第一个Matlab仿真实例
- 5.intent_activity
- java给定_Java – 在给定示例中使用super()
- 分布式系统:SrpingBoot整合Zookeeper和Dubbo的版本匹配问题
- Python深入-Python的内存管理
- C#LeetCode刷题之#674-最长连续递增序列( Longest Continuous Increasing Subsequence)
- php curl如何解决分页,一段PHP的分页程序,报错,该如何解决
- 萌新关于C#委托一点见解
- Yii2中使用自定义的数据库
- java嗅探网页视频_网页视频嗅探器( API钩子 )
- PHP-Web聊天室 一天即可打造自己的聊天室-严双双-专题视频课程
- 锦天科技被盛大收购 23岁创始人成亿万富翁
- 如何设置条码标签的打印数量
- Java判断经纬度点是否在给定区域内
- openCV ROI
- leetcode 1277
- fread函数详解 函数原型