-
博文分类专栏
- Jquery基础教程
-
- 文章:(15)篇
- 阅读:46569
- shell命令
-
- 文章:(42)篇
- 阅读:154244
- Git教程
-
- 文章:(36)篇
- 阅读:234885
- leetCode刷题
-
- 文章:(76)篇
- 阅读:131874
-
go中net/http包之http服务器使用详解2018-04-12 09:07 阅读(3793) 评论(0)
一、概述
要理解go语言中的http请求,首先需要明白ServeMux 和 Handler,http.ListenAndServe方法。
ServrMux 本质上是一个 HTTP 请求路由器(或者叫多路复用器,Multiplexor)。它会把收到的请求与预先定义的url路径进行匹配,一旦匹配成功,就执行匹配url相关的处理器(Handler)。下面是serverMux的定义:
type ServeMux struct { mu sync.RWMutex m map[string]muxEntry hosts bool // whether any patterns contain hostnames }
可以通过serverMux的Handle(pattern string, handler Handler)方法,将url和处理器,注册到serverMux上面。
Handler(处理器),负责处理http请求,即输出HTTP响应的头和正文。http.Handler是一个接口,定义如下:
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
可以看出,只要实现了serverHTTP(http.ResponseWriter, *http.Request)方法,就可以做为处理器。当然,http包,也自带了一波处理器,比如FileServer,NotFoundHandler 和 RedirectHandler。其实,serverMux也是处理器,因为它也实现了serverHTTP方法。
除了通过手动实现了ServeHTTP(ResponseWriter, *Request)方法来自定义处理器,有没有更简洁的方法呢?
当然是有的,通过查看http包中的代码,我们可以发现,其中定义了HandlerFunc,且实现了ServeHTTP(ResponseWriter, *Request)方法,如下:
type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r). func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
也就是说,我们可以创建一个HandlerFunc变量实例,即是一个处理器。
http.ListenAndServe是将某个处理器,监听在某个地址和端口上,一定请求过来,就调用该处理器的serverHTTP方法。
二、案例
1、案例1——通过实现ServeHTTP方法来创建处理器
上面提到过,实现了ServeHTTP(ResponseWriter, *Request)方法,就可以充当处理器。那么,我们就简单搞一个吧,如下:
type Student struct { name string } func (this Student) ServeHTTP(res http.ResponseWriter, req *http.Request) { fmt.Println("请求方法", req.Method) fmt.Println("请求头", req.Header) res.Write([]byte("hello world")) res.Write([]byte("my name is" + this.name)) }
现在开始测试那么一把:
st1 := Student{name: "张三"} http.ListenAndServe(":6350", st1)
请求curl http://127.0.0.1:6350,结果如下:
感觉so easy。请求过程如下:
图中handler即“st1”
2、案例2——通过创建http.HandlerFunc实例来创建处理器
既然http包,自带了很多处理器,我们就使用NotFoundHandler 处理器意思一下吧,代码如下:
package main import ( "net/http" ) func main() { http.ListenAndServe(":6350", http.NotFoundHandler()) }
通过查看http.NotFoundHandler()函数源码,可以看出,它实际上是创建了一个http.HandlerFunc实例。
类比,我们也可以通过http.HandlerFunc变量,来创建我们控制器。如下:
package main import ( "net/http" ) func main() { var handle http.HandlerFunc = http.HandlerFunc(sayHello) http.ListenAndServe(":6350", handle) } func sayHello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello world")) }
3、案例3——多控制器的处理
在上面的案例中,我们使用的都是单个控制器,所以当我们改变url的时候,如curl http://127.0.0.1:6350/hello、curl http://127.0.0.1:6350/blog,请求一直映射到这个处理器。是不是感觉不太友好呢?现实中的http服务器,都不是这么来的。
这个时候,就需要使用多路复用处理器,http包中已经为我们提供了http.ServeMux
首先,我们先自己实现一个简化版的瞅瞅。原理无非就是根据请求的uri,调用不同的处理器罢了。如下:
package main import ( "net/http" ) type MyMuxHandle struct { //定义一个多路复用控制器 handleMap map[string]http.Handler //保存uri和控制器的映射关系 } func (this *MyMuxHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) { //获取当前请求的url uri := r.RequestURI if handle, ok := this.handleMap[uri]; ok { handle.ServeHTTP(w, r) return } w.Write([]byte("not found handle")) } func main() { muxHandles := &MyMuxHandle{handleMap:make(map[string]http.Handler)} muxHandles.handleMap["/hello"] = http.HandlerFunc(sayHello) //添加控制器 muxHandles.handleMap["/bye"] = http.HandlerFunc(sayBye) //添加控制器 http.ListenAndServe(":6350", muxHandles) } func sayHello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello world")) } func sayBye(w http.ResponseWriter, r *http.Request) { w.Write([]byte("bye bye")) }
http.ServeMux的实现原理和上面也差不多,只是控制更加精细。我们在使用http.ServeMux实现一下,如下:
package main import ( "net/http" ) func main() { muxHandles := new(http.ServeMux) muxHandles.Handle("/hello", http.HandlerFunc(sayHello)) //添加控制器 muxHandles.Handle("/bye", http.HandlerFunc(sayBye)) //添加控制器 http.ListenAndServe(":6350", muxHandles) } func sayHello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello world")) } func sayBye(w http.ResponseWriter, r *http.Request) { w.Write([]byte("bye bye")) }