开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 27天,点击查看活动详情
前言
Go Web编程,标准库net/http
包是必学的,通过包中的ListenAndServe
函数,我们能很快的构建出一个Server。本文重点在net/http包的使用,并快速构建Server。
ListenAndServe初识
函数定义:
func ListenAndServe(addr string, handler Handler) error
简单示例:
func main() {
if err := http.ListenAndServe(":9090", nil); err != nil {
log.Fatal("ListenAndServe err:" + err.Error())
}
}
该函数,需要传入参数IP地址与端口组成的字符串和处理器(handler)。
如果 IP 地址与端口组成的字符串参数为空字符串,那么服务器默认使用 80 端口进行网络连接,如果处理器(handler)参数为 nil,那么服务器将使用默认多路复用器 DefaultServeMux。
自定义Server实例
net/http包,里边还定义了一个Server结构体,包含了很多对服务端的相关配置,例如IP地址端口、处理器、超时时间、context上下文等等。
type Server struct {
Addr string
Handler Handler
TLSConfig *tls.Config
ReadTimeout time.Duration
ReadHeaderTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxHeaderBytes int
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
ConnState func(net.Conn, ConnState)
ErrorLog *log.Logger
BaseContext func(net.Listener) context.Context
ConnContext func(ctx context.Context, c net.Conn) context.Context
inShutdown atomicBool
disableKeepAlives int32
nextProtoOnce sync.Once
nextProtoErr error
mu sync.Mutex
listeners map[*net.Listener]struct{}
activeConn map[*conn]struct{}
doneChan chan struct{}
onShutdown []func()
}
使用结构体 Server 构建一个实例:
server := http.Server{
Addr: ":9090",
Handler: nil,
}
if err := server.ListenAndServe(); err != nil {
log.Fatal("ListenAndServe err:" + err.Error())
}
处理器
一个处理器就是一个拥有 ServeHTTP 方法的接口,这个 ServeHTTP 方法需要接收两个参数,第一个参数是一个 ResponseWriter 接口,第二个参数是一个指向 Request 结构的指针。
DefaultServeMux 默认多路复用器,是多路复用器 ServeMux 结构的一个实例,ServeMux 也拥有 ServeHTTP 方法。
所以 DefaultServeMux 既是 ServeMux 结构的实例,也是处理器 Handler 结构的实例,因此 DefaultServeMux 不仅是一个多路复用器,还是一个处理器。但是 DefaultServeMux 是一个特殊的处理器,它唯一要做的就是根据请求的 URL 将请求重定向到不同的处理器。
自定义一个处理器(替代 DefaultServeMux):
type MyHandler struct{}
func (m MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello web "+time.Now().Format("2006-01-02 15:04:05"))
}
func main() {
server := http.Server{
Addr: ":9090",
Handler: &MyHandler{},
}
if err := server.ListenAndServe(); err != nil {
log.Fatal("ListenAndServe err:" + err.Error())
}
}
通过访问:http://0.0.0.0:9090/
和http://0.0.0.0:9090/xxx
,或者URI随意更改,网页都就会显示hello web 2023-03-01 20:29:38
这是因为使用自定义的处理器替代了默认多路复用器 DefaultServeMux,服务器不会再通过 URL 匹配来将请求路由至不同的处理器。
怎么解决这个问题呢?
使用多个处理器。使用 http 包的 Handle 函数绑定到 DefaultServeMux。
为了使用多个处理器去处理不同的 URL,我们不再在 Serve 结构的 Handler 字段中指定处理器,而是让服务器使用默认多路复用器 DefaultServeMux,
然后通过 http.Handle 函数将处理器绑定到 DefaultServeMux。http 包的 Handle 函数实际上是 ServeMux 结构的方法,为了操作便利而创建的函数,调用它们等同于调用 DefaultServeMux 的某个方法。
例如,调用 http.Handle,实际上就是在调用 DefaultServeMux 的 Handle 方法。
自定义多个处理器:
type MyHandler struct{}
func (m MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello web "+time.Now().Format("2006-01-02 15:04:05"))
}
type MyHandler2 struct{}
func (m MyHandler2) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello web2 "+time.Now().Format("2006-01-02 15:04:05"))
}
func main() {
server := http.Server{
Addr: ":9090",
}
http.Handle("/hello", MyHandler{})
http.Handle("/hello2", MyHandler2{})
if err := server.ListenAndServe(); err != nil {
log.Fatal("ListenAndServe err:" + err.Error())
}
}
这样定义后,只能正常访问到http://0.0.0.0:9090/hello
和http://0.0.0.0:9090/hello2
,其他访问都无效。
处理器函数
除了定义处理器Handler,我们还可以定义处理器函数,使用HandleFunc
进行加载
代码示例:
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello web "+time.Now().Format("2006-01-02 15:04:05"))
}
func Hello2(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello web2 "+time.Now().Format("2006-01-02 15:04:05"))
}
func main() {
server := http.Server{
Addr: ":9090",
}
http.HandleFunc("/hello", Hello)
http.HandleFunc("/hello2", Hello2)
if err := server.ListenAndServe(); err != nil {
log.Fatal("ListenAndServe err:" + err.Error())
}
}
正常访问到http://0.0.0.0:9090/hello
和http://0.0.0.0:9090/hello2
,其他访问都无效。
如果本文对你有帮助,欢迎点赞收藏加关注,如果本文有错误的地方,欢迎指出!