(1)type Handler
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
该接口用于开发者能够实现自己的Handler,只要实现ServeHTTP(ResponseWriter, *Request)方法即可
实现了ServeHTTP方法的结构都能够称之为handler对象,ServeMux会使用handler(如它的函数func (*ServeMux) Handle)并调用其ServeHTTP方法处理请求并返回响应。
(2)type HandlerFunc
type HandlerFunc func(ResponseWriter, *Request)
HandlerFunc 实现了ServeHTTP(w http.ResponseWrite, r *http.Request),因此可以将我们自己实现
func(w http.ResponseWrite, r *http.Request)类型的函数转化为实现了ServeHTTP的类型函数。
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
而ServeHTTP其实是调用f本身。
(3)type ServeMux--多路复用器
type ServeMux struct { mu sync.RWMutex //锁,由于请求涉及到并发处理,因此这里需要一个锁机制 m map[string]muxEntry //路由规则,一个string对应一个mux实体,这里的string就是注册的路由 hosts bool // whether any patterns contain hostnames }
type muxEntry struct{ explicit bool //是否精确匹配 h Handler //这个路由表达式对应哪个handler }
ServeMux为什么被称为多路复用器,其实是一个分发器,ServeMux也实现了ServeHTTP,只不过它的作用是找到收到的请求对应的处理函数。
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)
举个例子:
请求来了-->被ServeMux收到-->ServeMux调用它实现的ServeHTTP函数来找到这个请求对应的处理函数(也就是在ServeMux的结构体成员map[string]muxEntry中找到-->然后调用这个处理函数。
func NewServeMux
func NewServeMux() *ServeMux //NewServeMux创建并返回一个新的*ServeMux
var DefaultServeMux = NewServeMux() //DefaultServeMux是用于Serve的默认ServeMux。
func (*ServeMux) Handle
(mux *ServeMux) Handle(pattern string, handler Handler)
Handle注册HTTP处理器handler和对应的模式pattern。如果该模式已经注册有一个处理器,Handle会panic。
func (*ServeMux) HandleFunc
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
//HandleFunc注册一个处理器函数handler和对应的模式pattern,其实至始至终就调用了上面的Handle
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { if handler == nil { panic("http: nil handler") } mux.Handle(pattern, HandlerFunc(handler)) }
既然说完了ServeMux的注册路由函数,就先举个例子:
package main import ( "fmt" "net/http" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/hello", Hello) server := &http.Server{ Addr: "127.0.0.1:8080", Handler: mux, } server.ListenAndServe() } func Hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "hello ", r.URL.Path) }
请求(Path:"/hello")-->mux在自己的map中找Path对应的Handler(mux调用HandelFunc()注册到map中)
-->找到后调用。
注意上面调用的mux.HandleFunc是由mux调用的,而平时我们使用的是
http.HandleFunc("/", sayhelloName) http.Handle("/", sayhelloName)
http在包中声明并定义了一个ServeMux,名字叫DefaultServeMux,然后又声明了HandleFunc和Handle函数。
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }
func ListenAndServe
func ListenAndServe(addr string, handler Handler) error
该代码的执行过程是:
1.首先调用http.HandleFunc时:
- 调用了DefaultServeMux的HandleFunc
- 然后调用了DefaultServeMux的Handle
- 接着就是往DefaultServeMux的map[string]muxEntry中添加请求URL对应的路由规则,并且路由规则中存储对应的handler处理器
2.其次就是调用http.ListenAndServe(":12345", nil):
- 首先实例化Server
- 然后调用Server.ListenAndServe()
- 再调用net.Listen("tcp", addr)监听端口启动一个for循环,在循环体中Accept请求
- 然后对每个请求都实例化一个Conn,即srv.newConn(rw);并开启一个goroutine为这个请求进行服务go c.serve()
- 读取每个请求的内容 w, err := c.readRequest()
- 然后判断handler是否为空,如果没有设置handler(即第二个参数为nil时),handler就设置为DefaultServeMux
- 然后要选择DefaultServeMux中合适的handler,即要判断是否有路由能够满足这个request(循环遍历ServerMux的muxEntry)。如果有路由满足,则调用该handler的ServeHTTP;如果没有路由满足,则调用NotFoundHandler的ServeHTTP
func (*ServeMux) Handler
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)
Handler根据r.Method、r.Host和r.URL.Path等数据,返回将用于处理该请求的HTTP处理器。它总是返回一个非nil的处理器。如果路径不是它的规范格式,将返回内建的用于重定向到等价的规范路径的处理器。
Handler也会返回匹配该请求的的已注册模式;在内建重定向处理器的情况下,pattern会在重定向后进行匹配。如果没有已注册模式可以应用于该请求,本方法将返回一个内建的"404 page not found"处理器和一个空字符串模式。
其源代码为:
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { // CONNECT requests are not canonicalized. if r.Method == "CONNECT" { // If r.URL.Path is /tree and its handler is not registered, // the /tree -> /tree/ redirect applies to CONNECT requests // but the path canonicalization does not. if u, ok := mux.redirectToPathSlash(r.URL.Host, r.URL.Path, r.URL); ok { return RedirectHandler(u.String(), StatusMovedPermanently), u.Path } return mux.handler(r.Host, r.URL.Path) } // All other requests have any port stripped and path cleaned // before passing to mux.handler. host := stripHostPort(r.Host) path := cleanPath(r.URL.Path) // If the given path is /tree and its handler is not registered, // redirect for /tree/. if u, ok := mux.redirectToPathSlash(host, path, r.URL); ok { return RedirectHandler(u.String(), StatusMovedPermanently), u.Path } if path != r.URL.Path { _, pattern = mux.handler(host, path) url := *r.URL url.Path = path return RedirectHandler(url.String(), StatusMovedPermanently), pattern } return mux.handler(host, r.URL.Path) } // handler is the main implementation of Handler. // The path is known to be in canonical form, except for CONNECT methods. func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { mux.mu.RLock() defer mux.mu.RUnlock() // Host-specific pattern takes precedence over generic ones if mux.hosts { h, pattern = mux.match(host + path) } if h == nil { h, pattern = mux.match(path) } if h == nil { h, pattern = NotFoundHandler(), "" } return } func (mux *ServeMux) match(path string) (h Handler, pattern string) { // Check for exact match first. v, ok := mux.m[path] //匹配路由规则 if ok { return v.h, v.pattern } // Check for longest valid match. mux.es contains all patterns // that end in / sorted from longest to shortest. for _, e := range mux.es { if strings.HasPrefix(path, e.pattern) { return e.h, e.pattern } } return nil, "" }
那么当路由器ServeMux里面存储好了相应的路由规则m后,具体的请求又是怎么分发的呢:
- 当路由器ServeMux接收到请求request后就会调用
handler, _ : = mux.Handler(request) handler.ServeHTTP(w, request)
- 由上面源码中可见调用mux.Handler(request)的代码中又调用了mux.handler(host, r.URL.Path),他就是使用用户请求的URL和路由器中的路由规则map相匹配,匹配成功后返回map中的handler值
- 然后再调用该handler的ServeHTTP即可
5)Server
type Server
type Server struct { Addr string // 监听的TCP地址,如果为空字符串会使用":http" Handler Handler // 调用的处理器,如为nil会调用http.DefaultServeMux ReadTimeout time.Duration // 请求的读取操作在超时前的最大持续时间 WriteTimeout time.Duration // 回复的写入操作在超时前的最大持续时间 MaxHeaderBytes int // 请求的头域最大长度,如为0则用DefaultMaxHeaderBytes TLSConfig *tls.Config // 可选的TLS配置,用于ListenAndServeTLS方法 // TLSNextProto(可选地)指定一个函数来在一个NPN型协议升级出现时接管TLS连接的所有权。 // 映射的键为商谈的协议名;映射的值为函数,该函数的Handler参数应处理HTTP请求, // 并且初始化Handler.ServeHTTP的*Request参数的TLS和RemoteAddr字段(如果未设置)。 // 连接在函数返回时会自动关闭。 TLSNextProto map[string]func(*Server, *tls.Conn, Handler) // ConnState字段指定一个可选的回调函数,该函数会在一个与客户端的连接改变状态时被调用。 // 参见ConnState类型和相关常数获取细节。 ConnState func(net.Conn, ConnState) // ErrorLog指定一个可选的日志记录器,用于记录接收连接时的错误和处理器不正常的行为。 // 如果本字段为nil,日志会通过log包的标准日志记录器写入os.Stderr。 ErrorLog *log.Logger // 内含隐藏或非导出字段 }
Server类型定义了运行HTTP服务端的参数。Server的零值是合法的配置。
func (*Server) Serve
func (srv *Server) Serve(l net.Listener) error
Serve会接手监听器l收到的每一个连接,并为每一个连接创建一个新的服务go程。该go程会读取请求,然后调用srv.Handler回复请求。
func (*Server) ListenAndServe
func (srv *Server) ListenAndServe() error
ListenAndServe监听srv.Addr指定的TCP地址,并且会调用Serve方法接收到的连接。如果srv.Addr为空字符串,会使用":http"。
func (*Server) ListenAndServeTLS
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error
ListenAndServeTLS监听srv.Addr确定的TCP地址,并且会调用Serve方法处理接收到的连接。必须提供证书文件和对应的私钥文件。如果证书是由权威机构签发的,certFile参数必须是顺序串联的服务端证书和CA证书。如果srv.Addr为空字符串,会使用":https"。
举例:
package main import( "fmt" "net/http" "time" ) func sayhelloName(w http.ResponseWriter, req *http.Request){ fmt.Fprintf(w, "hello web server") //将字符串写入到w,即在客户端输出 } func main() { mux := http.NewServeMux() mux.HandleFunc("/", sayhelloName) //设置访问的路由 // err := http.ListenAndServe(":9090", nil) //设置监听的端口 // if err != nil { // log.Fatal("ListenAndServe : ", err) // } //如果使用的是Server,则等价于: server := &http.Server{ Addr: ":8000", ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, Handler: mux, } server.ListenAndServe() }
返回:
func (*Server) SetKeepAlivesEnabled
func (s *Server) SetKeepAlivesEnabled(v bool)
SetKeepAlivesEnabled控制是否允许HTTP闲置连接重用(keep-alive)功能。默认该功能总是被启用的。只有资源非常紧张的环境或者服务端在关闭进程中时,才应该关闭该功能。
标签:http,Handler,mux,handler,ServeMux,func,go,路由 From: https://www.cnblogs.com/dadishi/p/16989314.html