初识 Go 语言 Web 服务
Web Server 中 HandlerFunc, Handler, HandleFunc, Handle 理解
相信很多小伙伴在初学习Go Web服务时,都会遇到这么一个懵逼的问题?如图:
这其中的 HandleFunc, Handle, HandlerFunc, Handler 究竟是什么玩意?尤其是在学习别人代码时,一会使用 HandleFunc,一会又是Handle,一下子就分不清谁是谁了。
先从一个简单的例子说起代码如下:
package main
import (
"fmt"
"log"
"net/http"
)
type CustomHandler struct{}
func (CustomHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi")
}
func main() {
err := http.ListenAndServe("0.0.0.0:9527", new(CustomHandler))
if err != nil {
log.Fatal(err)
}
}
启动一个Web服务器的核心就是执行http.ListenAndServe方法,顺着这条藤去摸一摸它的瓜。
在 http.ListenAndServe(addr string, handler http.Handler) error
方法签名中 http.Handler
是一个接口,那么主要实现这个接口就能创建一个简单 web server,因此我创建了CustomHandler
struct。(当然自定义其他类型也行,实现ServeHTTP
接口即可)。
- 因此
http.Handler
是一个接口
那再来看看 http.HandlerFunc
, 它的定义是这样的
// 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.
// 方法签名,用于适配 func(ResponseWriter, *Request)此类参数方法
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
// HandlerFunc 实现 http.Handler 接口
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
由它的定义得知 HandlerFunc
是一个自定义的方法签名,它也实现了ServeHTTP
接口,其实HandlerFunc
就是为了将 func(ResponseWriter, *Request)
此类方法转换成HandlerFunc类型,从而实现http.Handler
接口;我用自定义String类型来举一个栗子:
package main
import (
"fmt"
)
type MyString string
func (s MyString) Say() {
fmt.Println("say: " + s)
}
func main() {
var hello = "Hello World!"
var newHello = MyString(hello)
newHello.Say() // 输出 "Hello World!"
}
如果看懂上面的例子,那么 http.HandlerFunc
也就懂了。
- 因此
http.HandlerFunc
是为了把常规函数转换成http.Handler
接下来解析http.Handle
和http.HandleFunc
, 上面第一个例子在启动过web server 时,执行的是http.ListenAndServe("0.0.0.0:9527", new(CustomHandler))
方法,其中第二参数是有值的;而另一种情况是第二参数传nil
的场景,当第二个参数为nil的时候,会使用http.DefaultServeMux
这个默认处理程序,其实http.ListenAndServe
注释也说的很清楚。
其中 http.Handle
和 http.HandleFunc
就是围绕http.DefaultServeMux
设计的。
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
// 解析:
// Handle在DefaultServeMux中注册给定模式的处理程序。
// ServeMux的文档解释了如何匹配模式。
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
// 解析
// HandleFunc在DefaultServeMux中为给定模式注册处理函数。
// ServeMux的文档解释了如何匹配模式。
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
因此 http.Handle
和 http.HandleFunc
是两个注册路由
函数,它给谁注册呢?给http.DefaultServeMux
; http.DefaultServeMux
是谁的默认实例呢?是http.ServeMux
。
如果我们不想像第一个例子那样自定义实现 http.Handler
,就是使用默认的http.DefaultServeMux
,下面是一个例子:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.Handle("/ping", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Pong")
}))
http.HandleFunc("/pong", func(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Ping")
})
if err := http.ListenAndServe("0.0.0.0:9527", nil); err != nil {
log.Fatal(err)
}
}
阶段总结
: 在 go 中启动一个 web server 非常简单,仅执行http.ListenAndServe(addr string, handler http.Handler)
函数即可,其中http.handler
是一个接口,在Go中,当函数的参数类型为接口时,可以传递nil
值作为参数;因此就有两种可能:- 要么实现
http.handler
接口-
- 自定义实现
http.Handler
接口,第三方HTTP框架或路由器都是自定义实现 http.handler
- 自定义实现
-
- 使用ServeMux创建一个实例
var mux := http.NewServeMux()
- 使用ServeMux创建一个实例
-
- 要么使用
http.ServeMux
默认实例DefaultServeMux
- 要么实现
了解一下 http.Server
上面说到通过执行 http.ListenAndServe 启动一个Web服务,最终执行的是http.Server
的ListenAndServe
方法。
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// If srv.Addr is blank, ":http" is used.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
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)
}
看到上面的 net.Listen("tcp", addr)
就可以知道 Go Web Server 最终还是使用 tcp 实现。
转载自:https://juejin.cn/post/7234468374179414072