Gin源码分析一:引擎 Engine
大部分的 Go 的 HTTP 框架都是在重写路由部分,已实现更快的更准确的路由查找,减少路由解析过程中消耗的时间,来提高框架的处理速度。
标准库 HTTP 的处理
Go 语言标准库处理 HTTP 请求的流程大致如下:
- 启动 HTTP 服务器:使用 http.ListenAndServe 或 http.ListenAndServeTLS 函数启动 HTTP 服务器。
- 处理请求:当服务器接收到 HTTP 请求时,它会使用与路径相对应的 http.Handler 实现处理请求。
- 调用处理程序:服务器会调用
ServeHTTP
方法,并将请求相关的信息作为参数传递给该方法。 - 路由匹配:在
ServeHTTP
方法中,通过比较请求的路径和已注册的路由,找到与请求匹配的路由。 - 调用处理函数:如果找到了匹配的路由,则调用与该路由相关的处理函数。
- 写入响应:处理函数通过
ResponseWriter
接口写入响应数据,以返回给客户端。
根据上述的处理方式,目前需要关注两个函数:ServeHTTP
和 ResponseWriter
。这是两个主要的处理方式。
Go 语言标准库中的主要方法有:http.Handle 和 http.HandleFunc 用于注册路由和处理函数;
http.ListenAndServe
和 http.ListenAndServeTLS
用于启动 HTTP 服务器;以及 http.ResponseWriter
和 http.Request
分别用于写入响应和处理请求。
ServeHTTP 方法
在 gin 中,通过 Engine
这个对象进行管理,这个对象是实现了 ServeHTTP
这个方法。这个方法是 Go 标准库 net/http
中声明的一个接口方法。通过该接口来做到路由的转发。
|
|
Gin 收到相关的请求,都会统一调用 ServeHTTP
方法,该方法会将接收到的参数等进行处理,例如寻找合适的处理器(Handler),最后返回统一的处理结果。
|
|
这个是整个 HTTP 框架的关键,是处理 HTTP 请求的入口也是出口。这里就会出现上文中需要关注的两个值。一个是 ServeHTTP
方法,另外是 ResponseWriter
。在这里无论是 request 还是 response 都是封装在 context 中进行的。
找到了相关的入口,接下来可以分析整个处理流程,先看主要的对象 Engine
。这也是我们使用 Gin 过程中第一使用的结构体。这个结构体较为复杂,里面定义了大量的变量。
根据我们之前看到的 ServeHTTP
方法中,首先使用到的变量有 pool
。这里的 pool 使用的 sync.Pool
这个类型,主要是用来重复使用的 Context
。这里直接从 pool 中取出 Context,并对 Context 的一些参数进行设置,最后调用 engine.handleHTTPRequest
方法。
engine.handleHTTPRequest
这个方法主要处理用户的 HTTP 请求,确定该请求的处理方法。简单的来说就:首先,获取请求的 HTTP 方法(如 GET 或 POST)和 URL 路径,并在需要时解码路径。然后,它搜索匹配该请求的处理树。如果找到了一个匹配的节点,它会将处理程序分配给请求的上下文(c),并写入 HTTP 响应头。如果未找到匹配的节点,则会通过 serverError
写入 “405 Method Not Allowed” 或 “404 Not Found” 的错误响应。
这样基本就是一个简单的 http 请求的处理过程。在代码中可以看到很多事情其实是由 [[02. 上下文(Context)]] 进行处理的。
如何Run
那么 Gin 框架是如何运行起来的。
|
|
这里的三个方法基本就是 Gin 的主要方式,从这三个方法会看明白 Gin 的 engine 如何工作的。
Default()
在 Default()
方法中,主要还是使用了 New()
方法来创建。
New()
方法主要对 Engine 进行了初始化。
之后设置了两个中间件(Middleware),用于日志和异常的 Recovery。
都出事完成后返回 engine。
Run()
这个方法主要是在给定的地址上进行监听和创建相关的 HTTP 服务。
首先会判断是否为不安全的代理 isUnsafeTrustedProxies()
。
代码调用了 isTrustedProxy
方法,主要是对 trustedCIDRs
这个变量进行检查。这个变量在 New()
的时候就会进行初始化。
|
|
通过输入的 IP 会和 trustedCIDRs 进行比较,看看是否包含在其中。如果不包含就返回 false。默认的表达式为所有的 IPv4 和 IPv6 都符合。
另外通过 resolveAddress
方法进行地址解析,其实是指对端口解析。这个方法的输入为一个切片。如果用户不输入的时候,通过读取环境变量获取端口 os.Getenv("PORT")
。如果无法获取环境变量的端口,那么就默认为 8080
。当用户输入具体的端口后,采用用户的输入。用户输入的数据过长,那么就会报错。
当上述都满足的时候,通过 http.ListenAndServe(address, engine.Handler())
进行启动。
更多 http 标准库工作原理可以看 HTTP源码解析
这样 Gin 框架就运行起来了。
相关内容
如果你觉得这篇文章对你有所帮助,欢迎赞赏~
赞赏