Article directory
go web example
We use the following example to introduce net/http
the simple use of golang packages.
package main
import "net/http"
func main() {
http.HandleFunc("/", helloWord) // 注册处理器
http.ListenAndServe(":8888", nil) // 监听8888端口,启动web项目
}
func helloWorld(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("Hello, World!"))
}
http.HandleFunc
http.HandleFunc
Register a handler in DefaultServeMux
.
DefaultServeMux
is provided by go by default ServeMux
.
// 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)
}
DefaultServeMux
:
When we do not create a ServeMux variable, it will be created by default.
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
ServeMux
ServeMux is a multiplexer for http requests. The mapping from the request path to the handler all exists in an attribute of the map data type, ie ServeMux.m
.
// ServeMux 是一个http请求的多路复用器.
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // contains all patterns that end in / sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
Let's look at the method in the previous section DefaultServeMux.HandleFunc(pattern, handler)
:
this method registers the path and the corresponding processor into ServeMux.
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{
h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
}
At the same time, ServeMux also implements the Handler interface:
The Handler interface only defines one ServeHTTP(ResponseWriter, *Request)
method for responding to http requests. ServeMux implements this method, and its main function is to distribute http requests to corresponding handlers.
// A Handler responds to an HTTP request.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
In the above code, mux.handler(r)
the handler will be found according to the url in the request, for example: /
find helloWorld
the function through the path.
And on the next line of code h.ServeHTTP(w, r)
, the function calls the ServeHTTP method to handle the request. Because the unified method of processing requests in go is ServeHTTP(ResponseWriter, *Request)
that the handler interface must be implemented.
In fact, in the above registration steps, there is such a statement mux.Handle(pattern, HandlerFunc(handler))
. The function of the second parameter HandlerFunc(handler)
is to convert the request processing function we wrote (for example: helloWord(rw http.ResponseWriter, r *http.Request)
) into HandlerFunc
a type. HandlerFunc
It is defined as follows:
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
HandlerFunc also implements the ServeHTTP method, so it is also the implementation of the Handler interface. We can see that this implementation essentially encapsulates the function written by the developer to comply with golang's specification for request processing.
Therefore, flexible use of Handler
interfaces can also help us write some web middleware such as filters.
ListenAndServe
Familiar with tcp programming, in fact, ListenAndServe
it is easy to understand the process. The process is generally to monitor the specified address, wait for the request, parse the message and call the corresponding handler after the request comes in. It will not be described in detail here.
We can notice that in the first example, the second parameter of ListenAndServe is nil. In this case, DefaultServeMux will be used by default when the request comes in.
// ListenAndServe listens on the TCP network address addr and then calls
// Serve with handler to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// The handler is typically nil, in which case the DefaultServeMux is used.
//
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{
Addr: addr, Handler: handler}
return server.ListenAndServe()
}