2.Golang的Http源码阅读(Handler注册)

先贴一段代码

package main

import (
    "net/http"
    "fmt"
    "log"
)

func hello(w http.ResponseWriter, r *http.Request)  {
    r.ParseForm()
    fmt.Printf("%+v\n", *r.URL)
    fmt.Fprintln(w, "Hello world")
}

func main() {
    http.HandleFunc("/", hello)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        log.Fatal(err)
    }
}

这里监听本地的9090端口,使用 http.HandleFunc 将URL为“/”的请求将其转向名为hello的方法。这是比较常见的Golang的简单Web的实现,但是看着会觉得很奇怪,建议先把代码跑起来,然后我们再来看看源码中Handler的定义先。

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

如代码中所示,Handler实际上一个接口,实现了 ServeHTTP(ResponseWriter, *Request) 这个函数,就相当于实现了一个Handler。通俗讲Handler就是处理输入输出流的函数,将Handler注册到路由器,等同于将特定的URL跟这个函数绑定起来,当客户端请求访问这个URL,路由器就会使用这个函数进行操作。
可能会有童鞋会疑问,hello这个函数并不是一个Handler,为什么可以作为Handler注册一个URL。这是因为这里有一个函数叫做HandleFunc,这里就讲讲HandleFunc的原理吧。先把源码列出来:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

HandleFunc传入一个字符串(URL)和一个func(ResponseWriter, Request),hello这个函数是符合func(ResponseWriter, Request)的要求的,然后使用DefaultServeMux进行处理,DefaultServeMux又是什么?在server.go的源码中可以轻松找到DefaultServeMux的定义

type ServeMux struct {
    mu    sync.RWMutex
    m     map[string]muxEntry
    hosts bool // whether any patterns contain hostnames
}
....
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux

由源码可以知道DefaultServeMux相当于一个公共的路由,一个公有变量,URL和Handle就是注册到这个路由上的。需要注意的是ServeMux的成员变量,有一个sync.RWMutex,了解过Golang并发的应该知道,这是一个读写锁(Mutiple read,single write lock, 多读单写锁,允许多个读操作并行执行,但写操作会完全互斥,在读取操作比较频繁时比sync.Mutex有着更好的性能表现),这应该也是考虑到作为Web服务器,读取操作会比较频繁。接下来看mux.Handle(pattern, HandlerFunc(handler))去到哪一步,应该看到这里有一个函数HandlerFunc(handler):

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

看到这里你就应该明白,为什么hello这个函数没有实现Handler方法也是一个Handler,因为HandlerFunc把hello强制实现ServeHTTP(w ResponseWriter, r *Request),所以hello这个函数也就是一个Handler。

这里是路由的最后一步了

type muxEntry struct {
    h       Handler
    pattern string
}

// 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)
    }
    mux.m[pattern] = muxEntry{h: handler, pattern: pattern}

    if pattern[0] != '/' {
        mux.hosts = true
    }
}

公有变量DefaultServeMux将Handler注册,这里就用到了读写锁以及一个私有结构muxEntry,到这里,路由注册就结束了。

    原文作者:HTTP
    原文地址: https://segmentfault.com/a/1190000015768983
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞