乐趣区

关于golang:浅析Go语言http服务handler对象底层原理

本文来源于: https://gobea.cn/blog/detail/15zqpwrq.html

最简略的 http 服务

对于 golang 来说, 创立一个 http 服务是轻而易举的事件, 如下, 咱们创立了一个非常简单的 http 服务, 监听 8899 端口, 只提供一个接口返回 hello world

package main
import (
    "fmt"
    "net/http"
)
func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "hello world")
    })
    http.ListenAndServe(":8899", nil)
}

当你在游览器输出 http://127.0.0.1:8899 时, 便能看到 hello world 的输入

http 服务

对于 golang 的 http 服务, 咱们次要了解两个对象,:

  • Handler, 它是申请的解决对象,Handler对象须要实现 ServeHTTP 办法,ServeHTTP执行的是咱们的业务逻辑, 个别咱们定义的 func(w http.ResponseWriter, r *http.Request) 的办法须要通过 http.HandlerFunc 包装为 Handler 对象
  • ServeMux, 它相当于一个路由注册器, 保留的申请门路 patternHandler对象的 map 表, 通过 pattern 找到对应的 Handler 对象, 而后执行 Handler 对象的 ServeHTTP 办法

简略的说,http 的执行对象是 handler, 而要成为handler 对象. 则必须实现 ServeHTTP 办法, 例如 HandlerFunc 实现了 ServeHTTP 办法, 所以它也是一个 handler 对象

handler 对象

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

// HandlerFunc 实现了 Handler 接口
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r)
}

server 从路由中找到 handler 对象, 执行 handler 对象中的 ServeHTTP 办法, 也就是说, 要作为路由的 Handler 对象, 须要实现 ServeHTTP 办法, 无关 handler 如下:

  • handler 函数, 具备 func(w http.ResponseWriter, r *http.Requests) 签名的函数, 须要通过 HandlerFunc 函数包装, 否则不能作为路由的 Handler 对象,
  • handler 处理函数, 通过 HandlerFunc 构造包装的 handler 函数,HandlerFunc实现了 ServeHTTP 接口办法的函数
  • handler 对象, 实现了 Handler 接口 ServeHTTP 办法的构造

注册路由 ServeMux

type ServeMux struct {
    mu    sync.RWMutex
    m     map[string]muxEntry
    hosts bool 
}

type muxEntry struct {
    explicit bool
    h        Handler
    pattern  string
}

// ServeMux 也领有 ServeHTTP 办法, 也就说 ServeMux 实现了 Handler 接口, 即 ServeMuX 其实也是一个 Handler 对象, 不过 ServeMux 的 ServeHTTP 办法不是用来解决 request 和 respone,而是用来找到路由注册的 handler
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)
}

如上,ServeMux.m保留了路由规定 pattern 以及对应的 Handler 解决对象, 另外 ServeMux 也领有 ServeHTTP 办法, 也就说 ServeMux 实现了 Handler 接口, 即 ServeMuX 其实也是一个 Handler 对象, 不过 ServeMux 的 ServeHTTP 办法不是用来解决 request 和 respone,而是用来找到路由注册的 handler

package main

import (
    "fmt"
    "net/http"
)

func main() {mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "hello world")
    })
    mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "hello world")
    })
    http.ListenAndServe(":8899", mux)
}

Server

http.ListenAndServe(":8899",mux)
// 等价于
serv := &http.Server{
        Addr:    ":8899",
        Handler: mux,
    }
serv.ListenAndServe()

http.ListenAndServe 源码如下:

func ListenAndServe(addr string, handler Handler) error {server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()}

起源

  • https://gobea.cn/blog/detail/…

参考

  • https://www.jianshu.com/p/be3…
退出移动版