在 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
的网页。