mux学习

mux简介

mux implement了一个请求路由器和调度符合要求的输入请求到相应的视图函数中,mux是http request multiplexer 就是http多路复用器

mux的特点是

  • implement了http.Handler接口 因此跟http.ServeMux是兼容的
  • 请求可以基于URL path path前缀 协议 头部 还有请求参数 http方法 或者使用客制的匹配器
  • URL host, path 还有query values可以使用正则表达式来匹配变量
  • 注册URL可以被构造 或者”反向” 这样有助于维护队资源的引用
  • 可以使用子路由 嵌套路由只有当父路由被匹配之后才会被指向 有利于路由的分类 以及在视图函数的编写上遵循模块化编程的准则

install

go get -u github.com/gorilla/mux

hello world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"github.com/gorilla/mux"
"net/http"
"log"
)

func test(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("lalalala"))
w.WriteHeader(http.StatusOK)
}

func main() {
r := mux.NewRouter()
//r.Host("localhost")
r.HandleFunc("/test", test)
log.Fatal(http.ListenAndServe("localhost:8080", r))
}

基本使用

声明一个路由

r := mux.NewRouter()

注册视图函数

1
2
3
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)

注意到上面的URL匹配那里是可以使用正则表达式来进行匹配变量的

视图函数编写

1
2
3
4
5
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Category: %v\n", vars["category"])
}

视图函数或者说handler都是两个默认参数

  1. w http.ResponseWriter
  2. r *http.Request

要注意第二http.request请求的参数指针类型的 不要写错 其它跟Java的servlet基本相同 使用writer讲返回内容输出到http response中 但是要注意视图函数都是void类型 没有返回值


路由匹配

匹配域名

r.Host("www.example.com")

匹配一个动态的子域名 可以使用正则

r.Host("{subdomain:[a-z]+}.domain.com")

匹配URL前缀

r.PathPrefix("/products/")

匹配http方法

r.Methods("GET", "POST")

匹配协议

r.Schemes("https")

匹配头部

r.Headers("X-Requested-With", "XMLHttpRequest")

匹配查询参数

r.Queries("key", "value")

使用客制匹配器

1
2
3
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
return r.ProtoMajor == 0
})

上面的各种匹配是可以一起声明的 向下面这样

1
2
3
4
r.HandleFunc("/products", ProductsHandler).
Host("www.example.com").
Methods("GET").
Schemes("http")


mux路由匹配冲突问题

如果一个请求跟两个路由都匹配 这就造成了冲突 这时候第一个会被成功匹配


子路由

子路由不仅仅很方便 而且有利于优化代码

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"github.com/gorilla/mux"
"net/http"
"log"
)

func test(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("lalalala"))
w.WriteHeader(http.StatusOK)
}

func testSubRouter(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("this is subrouter page"))
vars := mux.Vars(r)
key := vars["key"]
w.Write([]byte(key))
w.WriteHeader(http.StatusOK)
}

func main() {
r := mux.NewRouter()
s := r.PathPrefix("/hello").Subrouter()
s.HandleFunc("/{key}", testSubRouter)
r.HandleFunc("/test", test)
log.Fatal(http.ListenAndServe("localhost:8080", r))
}


静态文件

静态文件在mux中一般使用static的url前缀来匹配 这样非常方便


未完待续!

参考链接