Hello world!
第一步,用go语言搭建一个http版的‘hello world’程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
})
log.Println("Starting HTTP server...")
log.Fatal(http.ListenAndServe("localhost:4000", nil))
}
|
三个主要函数的简单分析
-
http.handleFunc() 函数的作用是建立路由映射。包含两个参数,第一个参数是指定的路由规则。第二个参数是,要调用的响应函数(这个函数必须符合函数签名func(http.ResponseWriter, *http.Request))。
-
func(w http.ResponseWriter, r *http.Request) {} 这个函数同样有两个参数,第一个参数是请求所对应的响应对象http.ResponseWriter ,包括响应码,响应头,响应体等。第二个对象就是请求对应的请求对象 *http.Request,包括http请求的所有信息。
1. http.ResponseWriter 我们就是通过调用这个对象的write方法来向响应体写入字符的。
-
http.ListenAndServe的作用是启动http服务器,并监听发送到指定地址和端口号的http请求。包含两个参数,第一个参数就是地址和端口号。第二个参数
http.handlefunc() 函数分析
实际上http.HandleFunc是标准库提供的一种简便写法,他的第二个参数必须为指定格式,是因为在http.HandleFunc函数内部会将传入的绑定函数转化为类型http.Handler,
而这个对象是go标准中的http请求处理器对象,该对象实现了http.Handler接口:
1
2
3
|
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
|
结论:http.HandleFunc的根本作用就是将一个函数转化为实现了http.Handler接口的类型(http.Handler)。 那么我们就可以自己创建一个类型并实现http.Handler接口。这样就可以替代handleFunc函数
实现代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package main
import (
"log"
"net/http"
)
func main() {
http.Handle("/", &helloHandler{})
log.Println("Starting HTTP server...")
log.Fatal(http.ListenAndServe(":4000", nil))
}
type helloHandler struct{}
func (_ *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
}
|
Http.ListrenAndServe(":4000”,nil)函数分析
首先来分析一下第二个参数nil,根据函数声明表示,nil代替的是一个实现了http.Handler接口的对象。
1
|
func ListenAndServe(addr string, handler Handler) error {...}
|
没错,这个handler就是跟上面一样,实现了handler接口的类型。我们可以直接使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package main
import (
"log"
"net/http"
)
func main() {
log.Println("Starting HTTP server...")
log.Fatal(http.ListenAndServe("localhost:4000", &helloHandler{}))
}
type helloHandler struct{}
func (_ *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
}
|
这个代码运行起来跟前面的是一样的,不过不能方便的将路由规则和函数进行绑定。
结论一: ListenAndServe()的第二个参数就是一个handler,能直接用但是不能提供路由绑定。
http.ServeMux函数分析—对http.Handle剖析
通过对Hande的源码分析,Handle 是对http.ServeMux对象(http.DefaultServeMux)封装了一层。
1
2
3
|
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
|
而这个http,serveMux是go语言的带有基本路由功能的服务复用器。除了用http.HandleFunc或http.Handle这类方法操作http.DefaultServeMux之外,也可以用http.NewServeMux来创建一个新的http.ServeMux对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.Handle("/", &helloHandler{})
log.Println("Starting HTTP server...")
log.Fatal(http.ListenAndServe("localhost:4000", mux))
}
type helloHandler struct{}
func (_ *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
}
|
结论:http.Handle方法,本质上是对DefaultServeMux这个对象的操作。
那么我们就可以,自己创建一个http.NewServeMux方法来对DefaultServeMux操作。
ListenAndServe是否也是对DefaultServeMux对象的封装呢
源码
1
2
3
4
|
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
|
虽然不是全局的封装,但也是用了http.server的对象。
结论:我们可以使用server写一个自定义程度较高的程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.Handle("/", &helloHandler{})
server := &http.Server{
Addr: ":4000",
Handler: mux,
}
log.Println("Starting HTTP server...")
log.Fatal(server.ListenAndServe())
}
type helloHandler struct{}
func (_ *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
}
|