golang中net/http中handler

http.Handle("/",nil)

http.HandleFunc("/",nil)

先看第一个方法

func Handle(pattern string, handler Handler) {

DefaultServeMux.Handle(pattern, handler)

}

handler接口

type Handler interface {

ServeHTTP(ResponseWriter, *Request)

}

实际调用的handle方法

// 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

}

}

第二个方法,接收pattern和一个函数签名为func(ResponseWriter, *Request)的函数类型

// 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 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))

}

这里HandlerFunc其实是一个类型,它实现了handle接口

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {

f(w, r)

}

由此我们发现两个注册方法最终调用的方法是一致的

最后我们可以看一下ServeMux结构

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

}

// 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

}

}

在这个方法中,我们可以看到,Handle方法会先判断传入的URI和handler是否合法,然后判断这个URI对应的处理器是否已经注册,然后将这个URI和handler对应的map写入ServeMux对象中。

注意,这里还有一个步骤。如果这个URI是以/结尾的,将会被送入es数组中,按长度排序。至于为什么会这么做,我们在后面的内容将会提到。

说完了这些,我们应该可以猜到这个ServeMux对象的作用了。他可以存储我们注册的URI和Handler,以实现当有请求进来的时候,可以委派给相对应的Handler的功能。

考虑到这个功能,那么我们也可以推断出,这个ServeMux也是一个Handler,只不过他和其他的Handler不同。其他的Handler处理的是具体的请求,而这个ServeMux处理的是请求的分配。

http.ListenAndServe(":9000",nil)

1

func ListenAndServe(addr string, handler Handler) error {

server := &Server{Addr: addr, Handler: handler}

return server.ListenAndServe()

}

Server的结构体

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.

//

// 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.

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

disableKeepAlives int32 // accessed atomically.

inShutdown int32 // accessed atomically (non-zero means we're in Shutdown)

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,是一个复杂的结构体,里面包含了设置服务器的很多参数,但是这里我们只聊Addr和Handler这两个属性。

Addr很容易理解,就是这个服务器所监听的地址。

Handler是处理器,负责把请求分配给各个对应的handler。在这里留空,则使用Golang默认的处理器,也就是上文中我们提到的实现了ServeHTTP方法的ServeMux。

接下来的运行函数

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)

}

func (srv *Server) Serve(l net.Listener) error {

...

for{

...

c := srv.newConn(rw)

c.setState(c.rwc, StateNew) // before Serve can return

go c.serve(connCtx)

}

}

简单来讲,在这个方法中,有一个死循环,他不断接收新的连接,然后启动一个协程,处理这个连接。我们来看看c.serve(connCtx)的具体实现:

func (c *conn) serve(ctx context.Context) {

...

serverHandler{c.server}.ServeHTTP(w, w.req)

...

}

type serverHandler struct {

srv *Server

}

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {

handler := sh.srv.Handler

if handler == nil {

handler = DefaultServeMux

}

if req.RequestURI == "*" && req.Method == "OPTIONS" {

handler = globalOptionsHandler{}

}

handler.ServeHTTP(rw, req)

}

这里的ServeHTTP方法逻辑很容易看出,如果最开始没有定义一个全局处理的Handler,则会使用Golang的默认handler:DefaultServeMux。

假设,我们这里使用的是DefaultServeMux,执行ServeHTTP方法。说到这里你是否有印象,我们在上一个章节里提到的:

所以,ServeMux也实现了ServeHTTP方法,他也是一个Handler。而对于他是怎么实现ServeHTTP方法的,我们也在后面的内容提到。

就是这里,对于ServeMux来说,他就是一个处理请求分发的Handler。

如果你学过Java,我跟你说他和ServletDispatcher很相似,你应该能理解吧。

处理serverHTTP

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {

...

h, _ := mux.Handler(r)

h.ServeHTTP(w, r)

}

在省去其他细节之后我们应该可以推断,这个mux.Handler®方法返回的h,应该是所请求的URI所对应的Handler。然后,执行这个Handler所对应的ServeHTTP方法。我们来看看mux.Handler®这个方法:

func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {

...

host := stripHostPort(r.Host)

path := cleanPath(r.URL.Path)

...

return mux.handler(host, r.URL.Path)

}

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, ""

————————————————

版权声明:本文为CSDN博主「smile_study1」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/smile_study1/article/details/108316015

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值