1 概述
包 net/http
提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。
快速开始:
package main
import (
"log"
"net/http"
)
func main() {
// 设置 路由
http.HandleFunc("/", IndexAction)
// 开启监听
log.Fatal(http.ListenAndServe(":8888", nil))
}
func IndexAction(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<h1 align="center">来自小韩说课的问候</h1>`))
}
运行程序,在浏览器上请求: localhost:8888
,你会看到我们的结果:
Go语言构建HTTP服务器还是很容易的。深入说明。
2 http.Server 类型
HTTP 服务器在 Go 语言中是由 http.Server
结构体对象实现的。参考 http.ListenAndServe()
的实现:
// 文件:src/net/http/server.go
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
可见过程是先实例化 Server
对象,再完成 ListenAndServe
。其中 Serve
对象就是表示 HTTP 服务器的对象。其结构如下
:
// 文件:src/net/http/server.go
type Server struct {
Addr string // TCP 监听地址, 留空为:":http"
Handler Handler // 调用的 handler(路由处理器), 设为 nil 表示 http.DefaultServeMux
TLSConfig *tls.Config // TLS 配置对象
ReadTimeout time.Duration // 请求超时时长
ReadHeaderTimeout time.Duration // 请求头超时时长
WriteTimeout time.Duration // 响应超时时长
IdleTimeout time.Duration // 请求空闲时长(keep-alive下两个请求间)
MaxHeaderBytes int // 请求头的最大长度
TLSNextProto map[string]func(*Server, *tls.Conn, Handler) // NPN 型协议升级出现时接管TLS连接的处理器函数映射表
ConnState func(net.Conn, ConnState) // 状态转换事件处理器
ErrorLog *log.Logger // 日志记录对象
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
定义了服务器需要的信息。
实例化了 Server
对象后,调用其 (srv *Server) ListenAndServe() error
方法。该方法会监听 srv.Addr
指定的 TCP 地址,并通过 (srv *Server) Serve(l net.Listener) error
方法接收浏览器端连接请求。Serve
方法会接收监听器 l 收到的每一个连接,并为每一个连接创建一个新的服务进程。
该 go 进程会读取请求,然后调用 srv.Handler
处理并响应。srv.Handler
通常会是 nil,这意味着需要调用 http.DefaultServeMux
来处理请求,这个 DefaultServeMux
是默认的路由,我们使用 http.HandleFunc
就是在 http.DefaultServeMux
上注册方法。
3 http.DefaultServeMux 默认路由对象
看 Go 的源码,了解 http.HandleFunc():
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
可以看出来,注册的函数被 DefaultServerMux
来使用了。注册的时候,需要 pattern,就是 URL 模式,以及处理该 URL 模式的函数。
DefaultServerMux
是 http.ServeMux
类型的一个默认实例,ServeMux
就是路由。其主要结构是一个映射 map,用来存储 URL 模式和相关处理函数的关系。参看源码可以看出来:
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry // 映射表
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
可以调用多次 http.HandleFunc()
来注册多个处理器。
URL 模式是固定的、由根开始的路径。处理器的 URL 模式匹配原则是 左侧长度优先匹配。
例如有模式 /path/article/
和 /path/
,如果请求的 URL 是 /path/other/
会由 /path/
注册的处理器来处理,而 URL 为 /path/article/42/
会由 /path/article/
来处理。
以斜杠结尾的模式代表一个由根开始的子树,就是以当前为前缀的都会匹配。因此 /
会匹配所有的未被其他注册的模式匹配的路径。
4 处理器
处理器可以由函数或实现 Handler
接口的对象来充当。Handler
接口就是要求对象实现和处理器函数一致的方法。看 http.Handler
接口的实现源码:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
我们使用函数 http.HandleFunc
注册处理函数,而使用 http.Handle
函数来注册满足 Handler
接口的处理对象。效果是一致的。
完!
原文出自:小韩说课
微信关注:小韩说课