Golang — Introduction to net/http

go web example

We use the following example to introduce net/httpthe 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.HandleFuncRegister a handler in DefaultServeMux.
DefaultServeMuxis 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 helloWorldthe 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 HandlerFunca type. HandlerFuncIt 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, ListenAndServeit 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()
}

Guess you like

Origin blog.csdn.net/weixin_45804031/article/details/125699733