基于 gorilla/mux 包实现路由定义和请求分发:基本使用
功能简介
前面我们介绍了 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 中的路由分组),以便不同路由可以共享通用条件,比如主机、路径前缀等。
使用入门
开始使用 mux.Router
之前,需要安装这个扩展包:
go get -u github.com/gorilla/mux
然后在我们可以这样实现创建第一个Web应用中演示的注册路由:
package main
import (
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
)
func sayHelloWorld(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) // 设置响应状态码为 200
fmt.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!
路由参数
现在,我们想要在路由定义中设置路由参数,例如 /hello/world
、/hello/学院君
,这可以通过如下方式来实现:
r.HandleFunc("/hello/{name}", sayHelloWorld)
你甚至还可以通过正则表达式限制参数字符:
r.HandleFunc("/hello/{name:[a-z]+}", sayHelloWorld)
以上规则表示路由参数只能是小写字母,不支持其它字符。
相应地,在闭包处理函数中,我们需要这样解析路由参数:
func sayHelloWorld(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
w.WriteHeader(http.StatusOK) // 设置响应状态码为 200
fmt.Fprintf(w, "Hello, %s!", params["name"]) // 发送响应到客户端
}
重启服务器,这次,我们可以通过 http://localhost:8080/hello/xueyuanjun
这种方式请求路由了:
Hello, xueyuanjun!
如果参数中包含中文,则返回 404 响应,表示路由匹配失败:
自定义处理器
和 http.ServeMux
一样,在 mux.Router
中,还可以将请求转发到自定义的处理器类,而不是闭包函数:
package main
import (
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
)
func sayHelloWorld(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
w.WriteHeader(http.StatusOK) // 设置响应状态码为 200
fmt.Fprintf(w, "Hello, %s!", params["name"]) // 发送响应到客户端
}
type HelloWorldHandler struct {}
func (handler *HelloWorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
w.WriteHeader(http.StatusOK) // 设置响应状态码为 200
fmt.Fprintf(w, "你好, %s!", params["name"]) // 发送响应到客户端
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/hello/{name:[a-z]+}", sayHelloWorld)
r.Handle("/zh/hello/{name}", &HelloWorldHandler{})
log.Fatal(http.ListenAndServe(":8080", r))
}
和上篇教程介绍的自定义路由处理器一样,这里自定义的 HelloWorldHandler
也要实现 Handler
接口声明的 ServeHTTP
方法,调用方式和之前一样,只是需要通过 r.Handle
方法,因为第二个参数传入的是处理器实例,而不是闭包函数。
重启服务器,我们就可以访问如下 HTTP 路由了:
以上,就是 gorilla/mux 扩展包提供的路由器 mux.Router
的基本使用,下篇教程,我们继续介绍它的更多路由匹配功能,包括限定主机、请求方法、scheme、路径前缀、请求头、查询字符串等,通过 mux.Router
,我们甚至可以构建出比 Laravel 路由还要强大的路由匹配规则。
1 Comment
签到?