二. 可复用的HTTP服务器

81 阅读3分钟

1. 回顾

我们之前已经实现了一个简单的HTTP服务器,能够对简单的HTTP请求进行处理,具体逻辑如下:

func main() {
   // 对8080端口进行监听
   l, _ := net.Listen("tcp", ":8080")
   // 获取和端口8080完成三次握手的tcp连接
   for {
      conn, _ := l.Accept()
      // 获取到conn连接
      c := NewConn(conn)
      // 读取到请求体
      req, _ := c.readRequest()
      if req.uri == "/hello" {
         //这里应该没有设置content-length头部字段,所以浏览器需要连接断开后,才知道数据已经读取完成了
         c.WriteData([]byte("hello"))
      } else {
         c.WriteData([]byte("hello world"))
      }
      c.bw.Flush()
      c.rwc.Close()
   }
}

那如果我们想要重新实现一个HTTP服务器,是不是要重复实现上面的代码,完成HTTP请求的解析,处理和对请求的响应,这样是不是太麻烦了。

2. 实现可复用HTTP服务器

通过观察上面代码,我们可以发现,除了不同的请求有不同的处理逻辑外,其他所有的逻辑都是完全相同的,不同的代码逻辑如下:

if req.uri == "/hello" {
     //这里应该没有设置content-length头部字段,所以浏览器需要连接断开后,才知道数据已经读取完成了
     c.WriteData([]byte("hello"))
 } else {
    c.WriteData([]byte("hello world"))
 }

那么针对此处不同,我们可以抽取出一个接口,让不同的服务器传入该接口不同的实现,从而方便实现不同的HTTP服务器。

我们观察上面具体的处理函数,需要根据Request中不同的uri来执行不同的处理逻辑,以及需要Conn来写入响应数据。根据该依据,接口定义如下:

type Handler interface {
   ServeHttp(conn *Conn, request *Request)
}

然后我们再提供一个构造HTTP服务器的函数,当需要创建一个新的HTTP服务器,只需要调用该函数,传入对应的处理函数即可。函数定义如下:

func ListenAndServe(addr string, handler Handler){
   // addr: 指定监听的端口
   // handler: HTTP服务器具体的处理函数
}

该函数的具体实现如下,完成了连接的建立,HTTP请求的解析以及响应体的构造,具体的业务处理逻辑则调用外部Handler接口的实现

func ListenAndServe(addr string, handler Handler){
   // 对8080端口进行监听
   l, _ := net.Listen("tcp", addr)
   // 获取和端口8080完成三次握手的tcp连接
   for {
      conn, _ := l.Accept()
      // 获取到conn连接
      c := NewConn(conn)
      // 读取到请求体
      req, _ := c.readRequest()
      // 执行具体的处理逻辑
      handler.ServeHttp(conn, req)
      // 当请求处理完成之后,需要将数据全部返回给客户端
      c.bw.Flush()
      c.rwc.Close()
   }
}

当我们要实现一个简单HTTP服务器时,我们只需要实现Handler接口,然后调用ListenAndServe函数,就能够启动一个HTTP服务了。

3. 具体示例

  1. 实现Handler接口,这里实现了http请求具体的处理函数
type SimpleWeb struct {
}

func (s *SimpleWeb) ServeHttp(c *Conn, req *Request) {
   if req.uri == "/hello" {
      //这里应该没有设置content-length头部字段,所以浏览器需要连接断开后,才知道数据已经读取完成了
      c.WriteData([]byte("hello"))
   } else {
      c.WriteData([]byte("hello world"))
   }
}
  1. 启动HTTP服务器
func main() {
   ListenAndServe(":8080", &SimpleWeb{})
}
  1. 这样一个简单的HTTP服务器就已经完成了,并且成功启动