golang http HandleFunc

golang_yh · · 24966 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

golang http的handle模块(一般也称为钩子模块),通过高级语言的匿名函数很容易实现这种内嵌功能的handle

我们一般这样使用golang的http HandleFunc来为http的server端做相应的处理

   /*********************************************/         http.HandleFunc("/", xxx_FUN)	err := http.ListenAndServe(":8080", nil)	if err != nil {	log.Fatal("ListenAndServe: ", err)	}   /*********************************************/

我们再深入源码仔细看看http.HandleFunc的实现

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {	DefaultServeMux.HandleFunc(pattern, handler) } // NewServeMux allocates and returns a new ServeMux. var DefaultServeMux = NewServeMux() func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} } type ServeMux struct {	mu    sync.RWMutex                   //一个读写锁	m     map[string]muxEntry            //一个path(patterns)的映射map	hosts bool                          // whether any patterns contain hostnames }

再来看看ListenAndServe的具体实现

func ListenAndServe(addr string, handler Handler) error {	server := &Server{Addr: addr, Handler: handler}	return server.ListenAndServe() } func (srv *Server) ListenAndServe() error {	addr := srv.Addr	if addr == "" {	addr = ":http"	}	ln, err := net.Listen("tcp", addr)	if err != nil {	return err	}	return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) } // Serve accepts incoming connections on the Listener l, creating a // new service goroutine for each.  The service goroutines read requests and // then call srv.Handler to reply to them. func (srv *Server) Serve(l net.Listener) error {	defer l.Close()	var tempDelay time.Duration // how long to sleep on accept failure	for {	rw, e := l.Accept()	if e != nil {	if ne, ok := e.(net.Error); ok && ne.Temporary() {	if tempDelay == 0 {	tempDelay = 5 * time.Millisecond	} else {	tempDelay *= 2	}	if max := 1 * time.Second; tempDelay > max {	tempDelay = max	}	srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)	time.Sleep(tempDelay)	continue	}	return e	}	tempDelay = 0	c, err := srv.newConn(rw)	if err != nil {	continue	}	c.setState(c.rwc, StateNew) // before Serve can return	go c.serve() //看来这个c.serve是处理的入口	} }

看来这个c.serve是处理的入口

// Serve a new connection. func (c *conn) serve() {	origConn := c.rwc // copy it before it's set nil on Close or Hijack	defer func() {	if err := recover(); err != nil {	const size = 64 << 10	buf := make([]byte, size)	buf = buf[:runtime.Stack(buf, false)]	c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)	}	if !c.hijacked() {	c.close()	c.setState(origConn, StateClosed)	}	}()	if tlsConn, ok := c.rwc.(*tls.Conn); ok {	if d := c.server.ReadTimeout; d != 0 {	c.rwc.SetReadDeadline(time.Now().Add(d))	}	if d := c.server.WriteTimeout; d != 0 {	c.rwc.SetWriteDeadline(time.Now().Add(d))	}	if err := tlsConn.Handshake(); err != nil {	c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)	return	}	c.tlsState = new(tls.ConnectionState)	*c.tlsState = tlsConn.ConnectionState()	if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {	if fn := c.server.TLSNextProto[proto]; fn != nil {	h := initNPNRequest{tlsConn, serverHandler{c.server}}	fn(c.server, tlsConn, h)	}	return	}	}	for {	w, err := c.readRequest()	if c.lr.N != c.server.initialLimitedReaderSize() {	// If we read any bytes off the wire, we're active.	c.setState(c.rwc, StateActive)	}	if err != nil {	if err == errTooLarge {	// Their HTTP client may or may not be	// able to read this if we're	// responding to them and hanging up	// while they're still writing their	// request.  Undefined behavior.	io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n")	c.closeWriteAndWait()	break	} else if err == io.EOF {	break // Don't reply	} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {	break // Don't reply	}	io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n")	break	}	// Expect 100 Continue support	req := w.req	if req.expectsContinue() {	if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {	// Wrap the Body reader with one that replies on the connection	req.Body = &expectContinueReader{readCloser: req.Body, resp: w}	}	req.Header.Del("Expect")	} else if req.Header.get("Expect") != "" {	w.sendExpectationFailed()	break	}	// HTTP cannot have multiple simultaneous active requests.[*]	// Until the server replies to this request, it can't read another,	// so we might as well run the handler in this goroutine.	// [*] Not strictly true: HTTP pipelining.  We could let them all process	// in parallel even if their responses need to be serialized.	serverHandler{c.server}.ServeHTTP(w, w.req) //这个是入口	if c.hijacked() {	return	}	w.finishRequest()	if w.closeAfterReply {	if w.requestBodyLimitHit {	c.closeWriteAndWait()	}	break	}	c.setState(c.rwc, StateIdle)	} }

Handler处理的入口就是serverHandler{c.server}.ServerHTTP(w,w.req),最终到HandleFunc的执行

func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {	if r.Method != "CONNECT" {	if p := cleanPath(r.URL.Path); p != r.URL.Path {	_, pattern = mux.handler(r.Host, p) //接下来处理	url := *r.URL	url.Path = p	return RedirectHandler(url.String(), StatusMovedPermanently), pattern	}	}	return mux.handler(r.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(), "" //如果handler对应的匿名函数为空,则返回默认的匿名函数	}	return } // 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) //接下来处理 } //接下来就初始时候执行的操作 func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {	mux.Handle(pattern, HandlerFunc(handler)) } func (mux *ServeMux) Handle(pattern string, handler Handler) {  //处理pattern	mux.mu.Lock()	defer mux.mu.Unlock()	if pattern == "" {	panic("http: invalid pattern " + pattern)	}	if handler == nil {	panic("http: nil handler")	}	if mux.m[pattern].explicit {	panic("http: multiple registrations for " + pattern)	}	mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern} //设置ServeMux的map	if pattern[0] != '/' {	mux.hosts = true	}	// Helpful behavior:	// If pattern is /tree/, insert an implicit permanent redirect for /tree.	// It can be overridden by an explicit registration.	n := len(pattern)	if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {	// If pattern contains a host name, strip it and use remaining	// path for redirect.	path := pattern	if pattern[0] != '/' {	// In pattern, at least the last character is a '/', so	// strings.Index can't be -1.	path = pattern[strings.Index(pattern, "/"):]	}	mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(path, StatusMovedPermanently), pattern: pattern}	} }

最后再看看通过mux匹配获取对应的map的操作:

func (mux *ServeMux) match(path string) (h Handler, pattern string) {	var n = 0	for k, v := range mux.m {	if !pathMatch(k, path) {   //匹配	continue	}	if h == nil || len(k) > n {	n = len(k)	h = v.h	pattern = v.pattern	}	}	return }



有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:golang_yh

查看原文:golang http HandleFunc

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

24966 次点击  
加入收藏 微博
1 回复  |  直到 2018-03-21 14:53:54
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传