##http与 router##
先看http 提供的强大简洁服务器端的功能
- HTTP响应模块
func ListenAndServe(addr string, handler Handler) error
这个方法就处理了所有的http请求。第二个参数如下
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
也就是实现了该接口的结构,均能够对http请求作出相应。看这个方法的参数大致就能猜出,这个方法是让使用者自己往RewponseWriter中写http header 以及http data。
type ResponseWriter interface {
Header() Header
Write([]byte) (int, error)
WriteHeader(int)
}
当第二个参数为空的时候,默认由系统的对象http.DefaultServeMux进行处理,看结构体
type ServeMux struct {
// contains filtered or unexported fields
}
这个对象会对Listen到的http请求进行路由。让不同的Handler进行处理。因此在Listen之前需要对ServeMux注册Handler。调用下面方法即可
func Handle(pattern string, handler Handler)
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
第一个方法的第二个参数是一个Handle类型接口,第二个方法是直接提供了一个Handle接口需要的接口方法。总之需要一个实现serveHTTP的结构体。而这个结构体则是studygolang很关键的一个模块。即router
- Router
Router这个结构体在studygolang中最重要的作用就是handler的路由,看ServeHttp提供的路由功能代码:
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Clean path to canonical form and redirect.
if p := cleanPath(req.URL.Path); p != req.URL.Path {
w.Header().Set("Location", p)
w.WriteHeader(http.StatusMovedPermanently)
return
}
var match RouteMatch
var handler http.Handler
if r.Match(req, &match) {
handler = match.Handler
setVars(req, match.Vars)
setCurrentRoute(req, match.Route)
}
if handler == nil {
if r.NotFoundHandler == nil {
r.NotFoundHandler = http.NotFoundHandler()
}
handler = r.NotFoundHandler
}
defer context.Clear(req)
handler.ServeHTTP(w, req)
}
在Router内嵌Route指针数组,通过Route来跟request进行匹配。而Route内部则存储http.Handler。如果匹配成功则,使用该Route内的Handler对请求进行响应。
type Route struct {
// Parent where the route was registered (a Router).
parent parentRoute
// Request handler for the route.
handler http.Handler
// List of matchers.
matchers []matcher
// Manager for the variables from host and path.
regexp *routeRegexpGroup
// If true, when the path pattern is "/path/", accessing "/path" will
// redirect to the former and vice versa.
strictSlash bool
// If true, this route never matches: it is only used to build URLs.
buildOnly bool
// The name used to build URLs.
name string
// Error resulted from building a route.
err error
// 过滤器链
FilterChain *FilterChain
}
通过该结构体的源码可以明白Route跟Path之间的关系是一一对应的,在每一个Route里面存储有一个Path。Route跟handle也是一一对应的,但是一个Route里面是可以有多个Filter的。首先是request 跟 Route之间的匹配。只要拿到request的URI就可以获取相匹配的Path。其次是Filter的调用与Handler的调用关系,就是Filter模块。
有疑问加站长微信联系(非本文作者)