摘要

由于Golang优秀的并发处理,很多公司使用Golang编写微服务。对于Golang来说,只需要短短几行代码就可以实现一个简单的Http服务器。加上Golang的协程,这个服务器可以拥有极高的性能。然而,正是因为代码过于简单,我们才应该去研究他的底层实现,做到会用,也知道为什么这么用。

在本文中,会以自顶向下的方式,从如何使用,到如何实现,一点点的分析Golang中net/http这个包中关于Http服务器的实现方式。内容可能会越来越难理解,作者会尽量把这些源码讲的更清楚一些,希望对各位有所帮助。

1 创建

首先,我们以怎么用为起点。

毕竟,知道了怎么用,才能一步一步的深入挖掘为什么这么用。

先来看第一种最简单的创建方式(省略了导包):

其实在这一部分中,代码应该很容易理解。就是先做一个映射,把需要访问的地址,和访问后执行的函数,写在一起。然后再加上监听的端口,就可以了。

如果你是一个Java程序员,你应该能发觉这个和Java中的Servlet很相似。也是创建一个个的Servlet,然后注册。

再来看看第二种创建方式,也一样省略了导包:

在这里,我们能发现相较于第一种方法,有些许的改动。

我们定义了一个结构体,然后又给这个结构体编写了一个方法。根据我们之前对于接口的概念:要实现一个接口必须要实现这个接口的所有方法

那么我们是不是可以推测:存在这么一个接口A,里面有一个名为ServeHTTP的方法,而我们所编写的这个结构体,他已经实现了这个接口A了,他现在是属于这个A类型的一个结构体了。

并且,在main函数中关于映射URI和方法的参数部分,需要调用实现了这个接口A的一个对象。

带着这个问题,我们可以继续往下。

2 注册

在第一部分,我们提到了两种注册方式,一种是传入一个函数,一种是传入一个结构体指针。

我们来看看http包内的源码:

先看一下这里的代码,他们被称为注册函数

HandleFuncmainfunc(pattern string, handler func(ResponseWriter, *Request))patternstringfunc(ResponseWriter, *Request)

然后我们继续看,在这个函数中,调用了这个方法:

DefaultServeMux
func (pattern string, handler Handler)DefaultServeMux

也就是说,无论我们使用哪种注册函数,最终调用的都是这个函数:

ServeMuxHandler
ServeMuxHandler
ServeHTTPHandler

注意到,在前面有一行代码是这样的:

HandlerFunc func(ResponseWriter, *Request)Handler
HandlerFunc

在Golang中,这是一种很特别的特性。我们可以将函数设置为一种类型,或者你可以理解成变量,你可以用一个变量名去表示这个函数,可以把这个函数赋值给某一个变量。

ServeHTTPHandlerFuncHandlerHandlerHandlerServeHTTP

这里比较绕,但是相信当你理解了之后,会感觉妙啊

HandlerServeMux
mmapURImuxEntrymuxEntryHandlerURImURIHandler
func (mux *ServeMux) Handle(pattern string, handler Handler)ServeMuxHandler
URIhandlerURIURIhandlermapServeMux
URI/es数组
ServeMuxURIHandlerHandler
ServeMuxHandlerHandlerHandlerServeMux

所以,ServeMux也实现了ServeHTTP方法,他也是一个Handler。而对于他是怎么实现ServeHTTP方法的,我们也在后面的内容提到。

3 监听

现在,让我们来聊聊main函数中的第二行:

按照惯例,我们来看一看这个方法的实现:

AddrHandler
Addr
HandlerhandlerServeHTTPServeMux
server.ListenAndServe()
ln, err := net.Listen("tcp", addr)addr
srv.Serve(ln)
c.serve(connCtx)
ServeHTTPc.server
ServeHTTPHandlerhandlerDefaultServeMux
DefaultServeMuxServeHTTP
所以,ServeMux也实现了ServeHTTP方法,他也是一个Handler。而对于他是怎么实现ServeHTTP方法的,我们也在后面的内容提到。
ServeMuxHandler
ServletDispatcher

4 处理

ServeHTTP
mux.Handler(r)hURIHandlerHandlerServeHTTPmux.Handler(r)
mux.match
ServeMuxkeyURIHandler
es数组URI/es数组中
URI
Handler

写在最后

首先,谢谢你能看到这里!

不知道你有没有理解我所说的内容,希望这篇文章可以给你一些帮助。

其实写这篇文章的目的是这样的,学完了Golang的基础之后作者准备开始研究Golang Web。但是查找各种资料后发现,并没有找到一条很合适的学习路线。然后本来作者打算去直接研究一个框架,如MeeGo,Gin等。但是又考虑到,框架只是用来解决问题的,学会了框架却不知道基础内容,有种知其然不知其所以然的感觉。

所以,作者打算从Golang的net/http包的源码开始,慢慢去了解怎么用原生的Go语言去建立一个HTTP服务器,然后去了解一下怎么进行缓存,做持久化等,这也是作者思考之后决定的一条学习路线。当能够把这些内容都研究明白之后,再去研究框架,去看这些框架是怎么解决问题的,可能才是比较合适的。

当然了,作者也是刚入门。所以,可能会有很多的疏漏。如果在阅读的过程中,有哪些解释不到位,或者理解出现了偏差,也请你留言指正。

再次感谢~

PS:如果有其他的问题,也可以在公众号找到作者。并且,所有文章第一时间会在公众号更新,欢迎来找作者玩~