博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Go Web:自带的ServeMux multiplexer
阅读量:6593 次
发布时间:2019-06-24

本文共 2941 字,大约阅读时间需要 9 分钟。

ServeMux简介

ServeMux扮演的角色是Multiplexer,它用来将将请求根据url路由给已注册的handler。如下图:

733013-20181125171455406-1479331184.png

上图中为3个路径注册了handler,一个是"/",另外两个是"/hello"和"/world"。这表示访问http://hostname/hello时,multiplexer会调用上图中对应的第二个handler,当访问http://hostname/world时,multiplexer会调用上图中对应的第三个handler,当不是这两个路径时,将调用第一个绑定在"/"上的handler。

注意,go的mux路由请求时,handler绑定的路径是否带尾随"/"是不一样的。带上尾随"/",表示此路径以及此路径下的子路径,都会调用注册在此路径上的handler

例如,当请求uri为"/hello/abc"的时候,不会调用"/hello"对应的handler,而是调用"/"对应的handler。只有注册handler的路径为"/hello/"时,uri为"/hello/abc"才会调用此handler。

实际上,当注册handler的路径带上尾随斜"/"时,在发起此路径的请求时,会通过301重定向的方式自动补齐这个尾随斜线,让浏览器发起第二次请求。例如,下面是注册handler的路径:

http.Handle("/hello/", &myHandler)

发起http://hostname/hello的请求时,会自动补齐为http://hostname/hello/,然后浏览器自动发起第二次请求。

ServeMux的匹配规则

ServeMux对每次流入的http请求的URL进行模式(pattern)匹配,然后调用注册在此pattern上的handler来处理这个请求。

Pattern部分可以定义为匹配host的模式。如果pattern以"/"开头,表示匹配URL的路径部分,如果不以"/"开头,表示从host开始匹配。

匹配时选择匹配匹配度最高(长匹配优先于短匹配)。例如为"/images/"注册了handler1,"/images/thumbnails/"注册了handler2,如果请求的URL路径部分为"/images/thumbnails/",将会调用handler2处理这个请求,如果请求的URL路径部分为"/images/foo/",将调用handler1处理。

注意,注册在"/"上的pattern会在其它模式匹配不上时被选中,因为所有请求都可以匹配这个pattern,只不过能匹配到的长度最短。

如果pattern带上了尾随斜线"/",ServeMux将会对请求不带尾随斜线的URL进行301重定向。例如,在"/images/"模式上注册了一个handler,当请求的URL路径为"/images"时,将自动重定向为"/images/"。除非再单独为"/images"模式注册一个handler。

如果为"/images"注册了handler,当请求URL路径为"/images/"时,将无法匹配该模式。

ServeMux详细解释

看看net/http/server.go文件中ServeMux的结构:

type ServeMux struct {    mu    sync.RWMutex    m     map[string]muxEntry    hosts bool // whether any patterns contain hostnames}type muxEntry struct {    h       Handler    pattern string}

结构看上去很简单。一个字段mu是RWMutex,m是注册handler和pattern的,hosts用于判断pattern是否包含了host的匹配。看看Handle()函数的定义会更清晰:

func (mux *ServeMux) Handle(pattern string, handler Handler) {    mux.mu.Lock()    defer mux.mu.Unlock()    if pattern == "" {        panic("http: invalid pattern")    }    if handler == nil {        panic("http: nil handler")    }    if _, exist := mux.m[pattern]; exist {        panic("http: multiple registrations for " + pattern)    }    if mux.m == nil {        mux.m = make(map[string]muxEntry)    }    mux.m[pattern] = muxEntry{h: handler, pattern: pattern}    if pattern[0] != '/' {        mux.hosts = true    }}// HandleFunc registers the handler function for the given pattern.func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    mux.Handle(pattern, HandlerFunc(handler))}

pattern为空或者handler为空时,都会panic。此外,想要定义重复的pattern,也会panic。如果pattern的第一个字符不是"/",则表示这个pattern是从主机名开始匹配的。

唯一需要注意的是,每个Handle()都会对ServeMux实例加上写锁。

以常用的DefaultServeMux为例,它是ServeMux的一个实例。当使用DefualtServeMux时,每调用一次Handle()或HandleFunc(),都意味着向这个DefaultServeMux的结构中的m字段添加pattern和对应的handler。由于加了写锁,如果使用多个goroutine同时启动多个web服务,在同一时刻将只能有一个goroutine启动的web服务能设置DefaultServeMux。当然,一般情况下不会使用goroutine的方式同时启动多个web服务。

第三方ServeMux

自带的默认的DefaultServeMux其实功能限制很大。比如请求的URL路径为"/images/123.png",想要匹配这个确实容易,但是想要取出其中的"123.png"字符串,DefaultServeMux就没法实现。

有一个非常强大的Gorilla工具包(www.gorillatoolkit.org),它有好几个功能,其中一个功能是提供multiplexer。

转载地址:http://yycio.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
Linux运维学习笔记之二:常用命令1
查看>>
snort安装常见问题及解决方法
查看>>
在ubuntu系统安装jdk
查看>>
很久没写了
查看>>
我的友情链接
查看>>
Cacti部署SOP
查看>>
Extjs - Panel组件
查看>>
收集参数及反转过程
查看>>
PPTP××× 数据分流
查看>>
mongodb 索引
查看>>
Citrix 宣布 XenServer 全面开源
查看>>
我的友情链接
查看>>
oracle 如果为空则输出0
查看>>
Spfa(最短路求解)
查看>>
使用linux-c编程实现简单的ls命令
查看>>
Q:按F12进行网络安装系统时,一直无法进入,提示加载失败?
查看>>
我的友情链接
查看>>
解决AutoCAD acmgd.dll ARX命令中发现异常
查看>>
[转]passport.js学习笔记
查看>>