一、介绍
go作为一个对web开发友好的语言,内置了net/http库。来帮助我们实现web服务器。
我们来看官方文档给我的最简单的一个文件服务器的实现。
func main() {
// Simple static webserver:
handler := http.FileServer(http.Dir("/usr/share/doc"))
_ = http.ListenAndServe(":8080", handler)
}
发现创建一个服务器主要有两步:
- 创建路由
- 启用服务器,并监听一个web端口
在启用服务器,并监听端口,我们一般用http.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主要传两个参数,端口号,以及handle路由。
我们可以使用 http.Handle()或者http.HandleFunc()来创建路由。
注册路由的话,我们主要有使用默认的DefaultServeMux,或者自己创建ServeMux。
二、使用DefaultServeMux创建路由的三种方式。
我们看一下Handler接口的定义
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
只要实现了 Handler 接口,就是一个有效的路由注册。
在官方默认的DefaultServeMux我们主要实现了三种方式,来看第一种。
2.1 通过官方默认类型fileHandler来创建
比如我们开始使用的,用来创建一个 静态文件web服务器的方法。
func main() {
// Simple static webserver:
handler := http.FileServer(http.Dir("/usr/share/doc"))
_ = http.ListenAndServe(":8080", handler)
}
主要是定义一个结构体,来实现Handler接口,如 http.FileServer()
就是用来创建了一个结构体fileHandler,而这个fileHandler拥有ServeHTTP(w ResponseWriter, r *Request)
方法。
源码如下:net/http/fs.go
func FileServer(root FileSystem) Handler {
return &fileHandler{root}
}
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
upath := r.URL.Path
if !strings.HasPrefix(upath, "/") {
upath = "/" + upath
r.URL.Path = upath
}
serveFile(w, r, f.root, path.Clean(upath), true)
}
2.2 http.Handle函数+自定义类型
在官方文档https://pkg.go.dev/net/http#Handle
上,我们可以看到官方的例子。
import (
"fmt"
"log"
"net/http"
"sync"
)
type countHandler struct {
mu sync.Mutex // guards n
n int
}
func (h *countHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
defer h.mu.Unlock()
h.n++
fmt.Fprintf(w, "count is %d\n", h.n)
}
func main() {
http.Handle("/count", new(countHandler))
log.Fatal(http.ListenAndServe(":8080", nil))
}
可以看到主要分三步,可以实现一个自定义类型的路由。
- 创建一个自定义类型
- 实现ServeHTTP(w http.ResponseWriter, r *http.Request)
- http.Handle()注册路由
2.3 使用HandleFunc 创建路由
这个方法是最简单的,相比第二种方法,我们可以先看下。
package main
import (
"fmt"
"net/http"
)
func index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello World")
}
func main() {
http.HandleFunc("/index", index)
http.ListenAndServe(":8080", nil)
}
我们可以打开网页 http://localhost:8080/index
发现非常简单的就实现了一个 Hello World
的输出。
我们在这里,包括第二种方法,调用http.ListenAndServe()的时候,在handle参数的时候,都传了一个nil。
原因是使用默认的 DefaultServeMux。
可以看一下 http.HandleFunc()的源码 src/net/http/server,go
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
在底层调用了DefaultServeMux。
我们使用 net/http库,在这个库里面,有一个全局的变量DefaultServeMux。
即使当http.ListenAndServe()我们这里handle参数不传的时候,就会调用默认的DefaultServeMux。
调用http.HandleFunc()/http.Handle()都是将处理器/函数注册到ServeMux的默认对象DefaultServeMux上。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。