前言
net/http 库的服务端实现
上两篇文章介绍了 http 客户端的实现,这篇文章看一下服务端的实现
服务端
使用 net/http
库可以快速搭建HTTP
服务,HTTP
服务端主要包含两部分:
- 注册处理器:
net/http.HandleFunc
函数用于注册处理器 - 监听端口:
net/http.ListenAndServe
用于处理请求
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello World")
}
func main() {
http.HandleFunc("/hello", hello)
http.ListenAndServe(":8080", nil)
}
注册处理器
直接调用net/http.HandleFunc
可以注册路由和处理函数:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
我们调用http.HandleFunc("/hello", hello)
注册路径处理函数,这里将路径/hello
的处理函数设置为hello
。处理函数的类型必须是:
func (http.ResponseWriter, *http.Request)
它调用HTTP
服务起的DefaultServeMux
处理请求,DefaultServeMux
本质是ServeMux
:
type ServeMux struct {
mu sync.RWMutex // 读写锁,保证并发安全,注册处理器时会加写锁做保护
m map[string]muxEntry // 路由规则,一个string对应一个mux实体,这里的string就是注册的路由表达式
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
**mu**
:需要加读写锁保证并发安全,注册处理器时会加写锁保证写map
的数据正确性,这个map
就是pattern
和handler
;**m**
:存储路由规则,key
就是pattern
,value
是muEntry
实体,muEntry
实体中包含:pattern
和handler
**es**
:存储的也是muxEntry
实体,因为我们使用map
存储路由和handler
的对应关系,所以只能索引静态路由,并不支持[path_param]
,所以这块的作用是当在map
中没有找到匹配的路由时,会遍历这个切片进行前缀匹配,这个切片按照路由长度进行排序;**hosts**
:这个也是用来应对特殊case
,如果我们注册的路由没有以/
开始,那么就认为我们注册的路由包含host
,所以路由匹配时需要加上host
;
func (mux *ServeMux) Handle(