在 Go 语言中, Handle 是专门用于处理 Web 请求的。当有一个 HTTP 请求时,Go 语言会创建一个 goroutine ,请求的过程由创建的这个 goroutine 完成。在 Go 中,有 http.DefaulServeMux 专门用来处理这个过程。

创建 Web Server

创建 Web Server 有两种方法:
- 使用
http.ListenAndServer() 创建 Web Server ,该函数有两个参数,第一个参数是网络地址,第二个参数是 handler 。 - 创建
http.Server 结构体,调用 server.ListenAndServe() 创建 Web Server ,使用该方法可以灵活配置。
首先介绍第一种方法,使用 http.ListenAndServer() 函数。该函数的第一个参数是网络地址,如果为 "" ,那么就是所有网络接口的 80 端口。第二个参数是 handler ,如果为 nil ,就是 DefaultServeMux 。DefaultServeMux 在 Go 语言中是一个 multiplexer ,可以看作路由器。
接下来我们使用 http.ListenAndServe() 函数创建一个 Web Server :
package main
import (
"net/http"
)
func main() {
http.ListenAndServe(":8080", nil)
}
运行该程序,打开浏览器,访问 http://localhost:8080/ ,会出现显示 404 page not found 的网页。因为这里我们还没有针对特定的路由编写对应处理的代码。
查看源代码可以看到 ListenAndServe() 函数:
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}它创建了一个 Server , http.Server 是一个结构体, Addr 字段表示网络地址,如果为 "" ,那么就是所有网络接口的 80 端口。Handler 字段,如果为 nil ,那么就是 DefaultServeMux 。DefaultServeMux 是一个 multiplexer ,也是一个 Handler ,用于转交给其他 Handler 请求。最后再由 Server 调用 ListenAndServe() 函数创建 Web Server ,这个函数没有参数:
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)
}了解了 http.ListenAndServer() 创建 Web Server 的原理后,我们可以使用创建 http.Server 结构体的方法,把上面的例子改成使用 http.Server 来实现相同的功能:
package main
import (
"net/http"
)
func main() {
server := http.Server{
Addr: "localhost:8080",
Handler: nil,
}
server.ListenAndServe()
}

单个 Handler 处理请求

使用 Handle 处理请求有两个方法:
- 使用
http.Handle() 函数,第二个参数是 Handler - 使用
http.HandleFunc() 函数,第二个参数是 Handler 函数
handler 是一个接口(interface), handler 定义了一个方法 ServeHTTP() ,该方法有两个参数,第一个参数是 ResponseWriter ,第二个参数是指向 Request 结构体的指针。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}下面我们自己做一个 Handler 用于处理 Web 请求:
package main
import (
"net/http"
)
type myHandler struct {}
func (handler *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World"))
}
func main() {
handler := myHandler{}
server := http.Server{
Addr: "localhost:8080",
Handler: &handler,
}
server.ListenAndServe()
}
运行该程序,打开浏览器,访问 http://localhost:8080/ ,会出现显示 Hello World 的网页。我们换一个地址 http://localhost:8080/hello 出现的还是显示 Hello World 的网页。这里所有请求的地址都会使用这个 Handler 处理请求,把 Hello World 输出。

多个 Handler 处理请求

要使用多个 Handler 处理请求,就不能指定 Server struct 里面的 Handler 字段值,使用 nil ,就是默认的 DefaultServeMux 。然后我们可以使用 http.Handle 将某个 Handler 附加到 DefaultServeMux 。
下面来看 http.Handle ,第一个参数表示 URL 后面跟的路径,第二个参数是 handler :
func Handle(pattern string, handler Handler)
接下来我们继续修改,创建两个 Handler ,分别是 aHandler 和 bHandler 。然后,再使用 http.Handle() 函数绑定路径 /a 对应的是 aHandler ,路径 /b 对应的是 bhandler 。
package main
import (
"net/http"
)
type aHandler struct {}
func (handler *aHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("AAA"))
}
type bHandler struct {}
func (handler *bHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("BBB"))
}
func main() {
ahandler := aHandler{}
bhandler := bHandler{}
server := http.Server{
Addr: "localhost:8080",
Handler: nil,
}
http.Handle("/a", &ahandler)
http.Handle("/b", &bhandler)
server.ListenAndServe()
}
运行该程序,打开浏览器,访问 http://localhost:8080/ ,会出现显示 404 page not found 的网页。我们访问地址 http://localhost:8080/a 出现的是显示 AAA 的网页。再访问地址 http://localhost:8080/b 出现的是显示 BBB 的网页。这样我们就实现了在多个 Handler 里面每个 Handler 对应不同的路径,对应不同的处理方法。
讲完了使用 http.Handle() 函数处理请求,接下来我们讲讲使用 http.HandleFunc() 函数处理多个请求。http.HandleFunc() 函数定义如下:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
接下来我们修改代码,添加两个函数:
package main
import (
"net/http"
)
func d(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("DDD"))
}
func e(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("EEE"))
}
func main() {
server := http.Server{
Addr: "localhost:8080",
Handler: nil,
}
http.HandleFunc("/c", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("CCC"))
})
http.HandleFunc("/d", d)
// http.HandlerFunc(e) 是类型转换
// 把 Handler 函数转化为 Handler
// 内部调用的还是 http.Handle 函数
http.Handle("/e", http.HandlerFunc(e))
server.ListenAndServe()
}
Go 有一个 HandlerFunc 的函数类型。可以将某个具有适当签名的函数 f ,适配成为一个 Handler ,而这个 Handler 具有方法 f :
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)
运行该程序,打开浏览器,访问 http://localhost:8080/c 出现的是显示 CCC 的网页。再访问地址 http://localhost:8080/d 出现的是显示 DDD 的网页,再访问地址 http://localhost:8080/e 出现的是显示 EEE 的网页。
