mux源码分析
http服务
http相关的网络服务,我们需要关注的都是客户端请求和服务端应答。在客户端请求(request)的过程中,重要的是路由。在服务端当接收到路由请求的时候,需要通过处理,再进行应答(response)。在接收request的过程中,路由是很重要的,这相当于是一个Multiplexer,Go中有内置的DefaultServerMux,也可以自定义Multiplexer。这里的Multiplexer的目的就是为了找到一个处理器函数(Handler),这样就可以对客户端进行响应了。
路由函数
func main() {
r := mux.NewRouter()
r.HandleFunc("/", HomeHandler)
r.HandleFunc("/products", ProductsHandler)
r.HandleFunc("/articles", ArticlesHandler)
http.Handle("/", r)
}
匹配部分
r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
读取变量
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Category: %v\n", vars["category"])
}
筛选条件
r.Headers("X-Requested-With", "XMLHttpRequest")
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
return r.ProtoMajor == 0
})
r.HandleFunc("/products", ProductsHandler).
Host("www.example.com").
Methods("GET").
Schemes("http")
子路由
r := mux.NewRouter()
s := r.Host("www.example.com").Subrouter()
s.HandleFunc("/products/", ProductsHandler)
s.HandleFunc("/products/{key}", ProductHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
中间件
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do stuff here
log.Println(r.RequestURI)
// Call the next handler, which can be another middleware in the chain, or the final handler.
next.ServeHTTP(w, r)
})
}
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.Use(loggingMiddleware)
使用 Router 的 HandleFunc
、Host
、 Methods
、 Schemes
、 Headers
等方法会创建一个路由并且为其添加相应类型 matcher,当然你也可以使用 MatcherFunc
来创建自己的 matcher。
gorilla/mux 会查找 Router 下的 Route 列表,找到是否有无匹配的路由,而 Route 会遍历其 matchers 列表来看看是否满足所有的 matchers,只要一个不匹配,则失败。
客户端
net/http包在编写golang web应用中有很重要的作用,它主要提供了基于HTTP协议进行工作的client实现和server实现,可用于编写HTTP服务端和客户端。
首先来看一下客户端代码:
// 用http包中默认的Client进行请求(因为没有指定Client)
resp, err := http.Get("http://example.com/")
...
resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
...
resp, err := http.PostForm("http://example.com/form",
url.Values{"key": {"Value"}, "id": {"123"}})
// 用自定义的Client进行请求
client := &http.Client{
CheckRedirect: redirectPolicyFunc,
}
resp, err := client.Get("http://example.com")
// ...
req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)
// ...
可以有两种方式,第一种比较直接,用默认即可;第二种比较复杂一点,是分布来完成的。
客户端的定义:
type Client stru