基于HTTP构建的网络应用包括两个端,即客户端(Client)和服务端(Server)。两个端的交互行为包括从客户端发出request、服务端接受request进行处理并返回response以及客户端处理response。所以http服务器的工作就在于如何接受来自客户端的request,并向客户端返回respond。
典型的http服务端处理流程:
服务器在接收到请求时,首先会进入路由(router),这是一个Multiplexer,路由的工作在于为这个request找到对应的处理器(handler),处理器对request进行处理,并构建response。GOlang实现的http server同样遵循这样的处理流程
package main
import (
"fmt"
"net/http"
)
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world")
}
func main() {
http.HandleFunc("/", indexHandler)
http.ListenAndServe(":8000", nil)
}
运行代码之后,在浏览器中打开localhost:8000就可以看到hello world 。这段代码先利用http.HandleFunc在跟路由/ 上注册了一个indexHandler,然后利用http.ListenAndServe开启监听。当有请求过来时,则根据路由执行对应的handler函数。
package main
import (
"fmt"
"net/http"
)
type indexHandler struct {
content string
}
func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, ih.content)
}
func main() {
http.Handle("/", &indexHandler{content: "hello world!"})
http.ListenAndServe(":8001", nil)
}
发现并没有进入监听状态,可能是端口被占用了
筛选8001端口的进程 netstat -ano |findstr “8001”
强制(/F参数)杀死 pid 为 9088 的所有进程包括子进程(/T参数):
taskkill /T /F /PID 592
再次运行 发现可以了 进入监听状态
Go实现的http服务步骤,首先注册路由,然后创建服务并开启监听即可。下文我们将从注册路由、开启服务、处理请求这几个步骤了解Golang如何实现http服务
http.HandleFunc和http.Handle都是用于注册路由,可以发现两者的区别在于第二个参数,前者是一个具有func(w http.ResponseWriter,r *http.Request)签名的函数,而后者是一个结构体,该结构体实现了func(w http.ResponseWriter ,r **http.Requests)签名的方法。
http.HandleFunc和http.Handle的源码如下:`
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
//HandleFunc registers the handler function for the given pattern
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
可以看到这两个函数 最总都由DefaultServeMux调用Handle方法来完成路由的注册。
这里我们遇到两种类型的对象:ServeMux和Handler
handler是一个接口:
type Handler interface{
serveHTTP(ResponseWriter, *Request)
}
Handler接口种声明了名为ServeHTTP的函数签名,也就是说任何结构只要实现了这个ServeHTTP方法,那么这个结构体就是一个Handler对象,其实go的http服务都是基于Handler进行处理,而Handler对象的ServeHTTP方法也正是用以处理request并构建response的核心逻辑所在。
回到上面的HandlerFunc函数,注意一下这行代码:
mux.Handle(pattern,HandleFunc(handler))
可能有人会误认为HandleFunc是一个函数,包装了传入handler函数,返回了一个Handler对象。然而这里HandlerFunc实际上是将handler函数做了一个类型转换,看下HandlerFunc的定义:
type HandlerFunc func(ResponseWriter,*Request)
//ServeHTTP call f(w,r)
func(f HandlerFunc) ServerHTTP(w ResponseWriter,r *Request){
f(w,r)
}
HandlerFunc是一个类型,只不过表示的是一个具有func(ResponseWriter, *Request)签名的函数类型,并且这种类型实现了ServeHTTP方法(在ServeHTTP方法中又调用了自身),也就是说这个函数其实就是一个Handler类型的对象,利用这种类型转换,我们可以将一个handler函数转换为一个Handler对象,而不需要定义一个结构体,再让这个结构体实现ServeHTTP方法
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)