【注意】最后更新于 December 2, 2019,文中内容可能已过时,请谨慎使用。
用于了解 http 包的一些运行机制
首先一个简单的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package main
import (
"fmt"
"net/http"
"strings"
"log"
)
func sayhelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数,默认不解析
fmt.Println(r.Form) //在终端中打印出表单内容
fmt.Println("Path", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println(r.Form["url_long"]) //输出指定的参数
for k,v := range r.Form{ //遍历打印出表单的值
fmt.Println("key",k)
fmt.Println("val", strings.Join(v, ""))
}
fmt.Fprint(w, "hello gpf!")
}
func main(){
http.HandleFunc("/", sayhelloName) //绑定路由与方法
err := http.ListenAndServe(":9090", nil) //监听 tcp:9090 端口
if err != nil {
log.Fatal("ListenAndServe: ",err)
}
}
|
文件目录下 go build http.go
./http
再直接访问http://localhost:9090
就能看到页面了
运行流程是什么呢?
大体的运行流程是介样:
- 创建 Listen Socket,监听 tcp 协议的 9090 端口,等待请求
- 收到请求后创建一个 client socket 去解析请求(request)
- 将请求内容交给 handle request 去处理,处理后返回给 client socket(handler)
- client socket 收到后台的处理结果返回给用户(response)
我们80%的逻辑都是在第3步内进行的,其他的已经有底层包帮我们实现了
我们的路由绑定机制是怎么实现的?
当走到以上的第3步的时候将会进入自己独立的 goroutine ,这也是用户访问互不影响的原因,
这一点和 nginx 很像,都是异步非阻塞的处理方式用来应对高并发
在最开始的例子当中我们绑定路由是直接将路由和函数指定了的,这里面发生了什么呢?
当调用
1
|
http.HandleFunc("/", sayhelloName)
|
时 因为没有对监听函数传递第二个参数,传了个 nil 进去
1
|
http.ListenAndServe(":9090", nil)
|
nil 的位置本应该是一个 handler,如果为空的话,将调用默认的 handler ,即 DefaultServeMux
,
因为它实现了 Handler
接口所以能处理请求, Handler
接口的内容是
1
2
3
|
type Handler interface{
ServeHTTP(ResponseWriter, *Request)
}
|
这个方法就是我们的路由实现器,我们所有的路由指向的方法都是在这里处理的,
可是为什么我的sayhelloName()
并没有实现 Handler
的接口但还是正常运行了,这怎么回事呢?
这是因为 http.HandleFunc()
帮你完成了这个接口的实现,文档
自己实现一个简易的路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
package main
import (
"fmt"
"net/http"
)
//设定一个空的接口体来承载接口
type MyMux struct{}
//实现 Handler 接口,在这里处理路由相关的内容
func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
sayHello(w, r)
return
}
if r.URL.Path == "/login" {
loginPage(w, r)
return
}
http.NotFound(w, r)
return
}
func sayHello(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello route '/' !")
}
func loginPage(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "this is login page")
}
func main() {
//实例化结构体
mux := &MyMux{}
//当做 handler 注入到监听服务当中去
http.ListenAndServe(":9090", mux)
}
|
如果想自己实现路由的处理也可以这样试试,但是我不想平白的用一个空的 struct 去承载这个啊,
我们可以试试这个
ServeMux
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package main
import (
"fmt"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "this is login page")
})
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello your first page")
})
http.ListenAndServe(":9090", mux)
}
|
说了这么多其实还是云里雾里的,不过没关系,可以先放在这里,等用的多了自然也能想开了
文章作者
GPF
上次更新
2019-12-02
(521dbfe)