如果要更深入的理解golang
的http
处理,那么net/http
包的源码就得研读一番。
我们使用原生的golang来处理http处理,一般我们的代码是这样写的。
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
29
30
31
32
|
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
// set route and handler 设置路由及处理请求
http.HandleFunc("/hello", helloHandle)
http.HandleFunc("/test", testHandle)
http.HandleFunc("/", indexHandle)
fmt.Println("Listening at port 8080...")
// listen at port 8080 监听8080端口
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
func indexHandle(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "index")
}
func helloHandle(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func testHandle(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "test...")
}
|
我们可以很容易的启动一个http
服务器,并处理相关的http
请求。在上面的代码中,我们使用到了http
包中的两个方法,一个是HandleFuc
,一个是ListenAndServe
。
可以从net/http包下的server.go中找到对应的代码:
1
2
3
4
5
6
|
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
|
看到上面一段代码,我们发现HandleFunc
实际上是将所有权交给serveMux
,serveMux
又是什么?简单点说,serveMux
是一个多路复用器,其作用就是将
请求的路由与handler
绑定。
1
2
3
4
5
6
|
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
|
从结构上看,serveMux
将路由以map
的方法存储至m
中,mu
为了防止并发加的锁,当我们的请求的uri到达后,如果没有自定义mux,那将会走defaultMux进行路由匹配,
mux会调用其match方法,找到对应的muxEntry,然后处理对应的请求。
通过上面的分析,我们知道HandleFunc只是用于将路由绑定至mux中,而mux如果我们不自己定义,就是走的defaultServeMux。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// If srv.Addr is blank, ":http" is used.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
func (srv *Server) ListenAndServe() error {
if srv.shuttingDown() {
return ErrServerClosed
}
addr := srv.Addr
if addr == "" {
addr = ":http"
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return srv.Serve(ln)
}
|
ListenAndServe 是将http服务启动,监听相应的端口,该方法将初始化Server结构体。
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
type Server struct {
// Addr optionally specifies the TCP address for the server to listen on,
// in the form "host:port". If empty, ":http" (port 80) is used.
// The service names are defined in RFC 6335 and assigned by IANA.
// See net.Dial for details of the address format.
Addr string
Handler Handler // handler to invoke, http.DefaultServeMux if nil
// TLSConfig optionally provides a TLS configuration for use
// by ServeTLS and ListenAndServeTLS. Note that this value is
// cloned by ServeTLS and ListenAndServeTLS, so it's not
// possible to modify the configuration with methods like
// tls.Config.SetSessionTicketKeys. To use
// SetSessionTicketKeys, use Server.Serve with a TLS Listener
// instead.
TLSConfig *tls.Config
// ReadTimeout is the maximum duration for reading the entire
// request, including the body. A zero or negative value means
// there will be no timeout.
//
// Because ReadTimeout does not let Handlers make per-request
// decisions on each request body's acceptable deadline or
// upload rate, most users will prefer to use
// ReadHeaderTimeout. It is valid to use them both.
ReadTimeout time.Duration
// ReadHeaderTimeout is the amount of time allowed to read
// request headers. The connection's read deadline is reset
// after reading the headers and the Handler can decide what
// is considered too slow for the body. If ReadHeaderTimeout
// is zero, the value of ReadTimeout is used. If both are
// zero, there is no timeout.
ReadHeaderTimeout time.Duration
// WriteTimeout is the maximum duration before timing out
// writes of the response. It is reset whenever a new
// request's header is read. Like ReadTimeout, it does not
// let Handlers make decisions on a per-request basis.
// A zero or negative value means there will be no timeout.
WriteTimeout time.Duration
// IdleTimeout is the maximum amount of time to wait for the
// next request when keep-alives are enabled. If IdleTimeout
// is zero, the value of ReadTimeout is used. If both are
// zero, there is no timeout.
IdleTimeout time.Duration
// MaxHeaderBytes controls the maximum number of bytes the
// server will read parsing the request header's keys and
// values, including the request line. It does not limit the
// size of the request body.
// If zero, DefaultMaxHeaderBytes is used.
MaxHeaderBytes int
// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
// If TLSNextProto is not nil, HTTP/2 support is not enabled
// automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
// ConnState specifies an optional callback function that is
// called when a client connection changes state. See the
// ConnState type and associated constants for details.
ConnState func(net.Conn, ConnState)
// ErrorLog specifies an optional logger for errors accepting
// connections, unexpected behavior from handlers, and
// underlying FileSystem errors.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
// BaseContext optionally specifies a function that returns
// the base context for incoming requests on this server.
// The provided Listener is the specific Listener that's
// about to start accepting requests.
// If BaseContext is nil, the default is context.Background().
// If non-nil, it must return a non-nil context.
BaseContext func(net.Listener) context.Context
// ConnContext optionally specifies a function that modifies
// the context used for a new connection c. The provided ctx
// is derived from the base context and has a ServerContextKey
// value.
ConnContext func(ctx context.Context, c net.Conn) context.Context
inShutdown atomicBool // true when server is in shutdown
disableKeepAlives int32 // accessed atomically.
nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error // result of http2.ConfigureServer if used
mu sync.Mutex
listeners map[*net.Listener]struct{}
activeConn map[*conn]struct{}
doneChan chan struct{}
onShutdown []func()
}
|
从server的结构中可以发现包含handler类型,从server的handler的注释中可以看出,handler就是用于多路复用路由处理的,Handler是一个接口类型,只要
实现了Handler接口的方法,都可以当作server的handler,从这里可以发现,我们如果不想用defaultServeMux来做多路复用处理器,我们自定义的一个CustomerHandler实现
ServeHTTP(ResponseWriter, *Request)方法即可。
Handler接口定义如下:
1
2
3
|
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
|
httpServer的接收到request处理的过程是和复杂的,目前也不太想细细研究这部分的内容,知道经过一系列的处理,最终将处理的能力交给实现了ServeHTTP的handler即可。