因为创建一个处理器和多路复用器唯一需要做的就是实现ServeHTTP
方法,所以通过自行创建多路复用器来代替net/http
包中的ServeMux
是完全可行的,并且目前市面上已经出现了很多第三方的多路复用器可供使用,比如,Gorilla Toolkit(www.go-rillatoolkit.org)就是一个非常优秀的第三方多路复用器包,它提供了mux
和pat
这两个工作方式非常不同的多路复用器,而本节将要介绍的则是另一个高效的轻量级第三方多路复用器——HttpRouter
。
ServeMux
的一个缺陷是无法使用变量实现URL模式匹配。虽然在浏览器请求/threads
的时候,使用ServeMux
可以很好地获取并显示论坛中的所有帖子,但如果浏览器请求的是/thread/123
,那么要获取并显示论坛里面ID为123的帖子就会变得非常困难。程序必须对URL进行语法分析才能提取出URL当中的帖子ID。此外,因为受ServeMux
实现URL模式匹配的方式所限,如果我们想要通过/thread/123/post/456
这样的URL从ID为123的帖子中获取ID为456的回复,就必须在程序里面进行大量复杂的语法分析,并因此给程序带来额外的复杂度。
与ServeMux
不同,HttpRouter
包并没有上面提到的这些限制。本节将对HttpRouter
包最重要的一部分特性进行介绍,关于这个包的更详细的说明可以在它的文档页面里面看到:https://github.com/julienschmidt/httprouter
。代码清单3-12展示了一个使用HttpRouter
实现的服务器。
代码清单3-12 使用HttpRouter
实现的服务器
package main
import(
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request, p httprouter.Params){
fmt.Fprintf(w,"Hello, %s!\n" , p.ByName("name"))
}
func main(){
mux := httprouter.New()
mux.GET("/hello/:name", hello)
server := http.Server{
Addr: "127.0.0.1:8080",
Handler: mux,
}
server.ListenAndServe()
}
这个程序中的大部分代码都和之前展示过的代码一样,只是涉及多路复用器的部分代码跟之前有所不同。在这段代码里,程序通过调用New
函数来创建一个多路复用器:
mux := httprouter.New()
这个程序不再使用HandleFunc
绑定处理器函数,而是直接把处理器函数与给定的HTTP方法进行绑定:
mux.GET("/hello/:name", hello)
这段代码会把给定URL的GET
方法与hello
处理器函数进行绑定,当浏览器向这个URL发送GET
请求时,hello
函数就会被调用,但如果浏览器向这个URL发送除GET
请求之外的其他请求,hello
函数则不会被调用。需要注意的是,被绑定的URL包含了具名参数(named parameter),这些具名参数会被URL中的具体值所代替,并且程序可以在处理器里面获取这些值。
跟之前的处理器函数相比,现在的hello
处理器函数也发生了变化,它不再接受两个参数,而是接受3个参数。其中第三个参数Params
就包含了之前提到的具名参数,具名参数的值可以在处理器内部通过ByName
方法获取:
func hello(w http.ResponseWriter, r *http.Request, p httprouter.Params){
fmt.Fprintf(w,"Hello, %s!\n" , p.ByName("name"))
}
程序的最后一个变化是它不再使用默认的DefaultServeMux
,而是通过将HttpRouter
传递给Server
结构来使用这个多路复用器:
server := http.Server{
Addr: "127.0.0.1:8080",
Handler: mux,
}
server.ListenAndServe()
现在,如果我们在终端上执行go build
命令,那么编译器将返回一个错误:
$ go build
server.go:5:5: cannot find package "github.com/julienschmidt/httprouter"
in any of: /usr/local/go/src/github.com/julienschmidt/httprouter (from $GOROOT)
/Users/sausheong/gws/src/github.com/julienschmidt/httprouter (from $GOPATH)
出现这个错误的原因在于,我们虽然指定了HttpRouter
库,但这个第三方库在我们的电脑上并不存在,得益于Go语言强大且易用的包管理系统,我们只需要执行以下命令就可以解决这个问题了:
$ go get github.com/julienschmidt/httprouter
在电脑连接了网络的情况下,这个命令会从HttpRouter
的GitHub
主页上下载HttpRouter
包的源代码,并将其存储到$GOPATH/src
目录中。在此之后,当我们再次执行go build
命令尝试编译代码清单3-12所示的服务器时,编译器就会导入HttpRouter
的代码,并对整个服务器进行编译。