Preface
转型路很艰难,所以最近思考了一下,发现自己会的东西多,但是精通和深入的东西少。
后续转型只会更难。决定细心研读一款框架的代码,理解其核心会对后续大有裨益。
golang 比较流行的 web 框架就那么几个:
- begoo
- gin
- httprouter:gin是基于此框架的
begoo 是国人的作品,但是之前了解过一下,比较重,所以选择轻量一些的 gin 作为研究对象。
Contents
研究 gin 是从他的源代码根目录开始的,第一个文件是 auth.go,在 auth.go 的第一个 public 方法 BasicAuthForRealm 中看到了 gin.Context 的使用,于是导航到 gin.Context 看看
Context
Context 是 gin 的核心之一。他是用来在中间件之间传递变量,管理流程,比如验证请求的 JSON 数据和渲染 JSON 响应。
1 | type Context struct { |
常量部分
Context.go 的代码注释和逻辑分块做的非常好,他的代码是按照逻辑进行分块的。
第一部分肯定是常量定义,首先声明的几个变量都是来自 gin-gonic/gin/binding
的;
接着是 abortIndex = math.MaxInt8/2 也就是最大中间件深度,也就是个数;
实例化相关部分
- reset: 私有方法,看名字就知道是重置 Context
- Copy: 看名字就知道是复制当前 Context ,复制的时候没有复制处理函数和中间件,以及 *writemem 的 ResponseWriter,因为如果全盘复制的话,会导致两个 Context 也就是两个请求共用一个处理链和响应用的 Writer ,会造成当前请求没法响应
- HandlerName: 返回主处理函数的名字
- Handler: 主处理函数,也就是 handlers.last
流程控制部分
- Next: 只能在中间件里调用,用于执行中间件链条中下一个中间件
- IsAborted: 返回当前 Contexxt 是否已经中断,其实就是判断当前索引是否大于等于 abortIndex
- Abort: 强行中断当前 Context 的执行,也就是将当前的索引设置为 abortIndex
- AbortWithStatus: 调用
Abort
并将指定的状态码写入 header,例如,鉴权验证失败,立刻调用此方法并传入状态码401,也就是鉴权失败 - AbortWithJSON: 先调用
Abort
但后调用JSON
,也就是将错误信息以JSON的方式响应 - AbortWithError: 先调用
AbortWithStatus
,然后将错误通过Error
方法将错误信息推入context.errors
中
错误管理部分
- Error: 将错误附加到当前 Context 中,也就是将错误推入 Context 的 errors 中,解析请求的过程中遇到的错误都可以调用此方法处理,可以制作一个中间件搜集这些错误,然后将他们一起记录到数据库中,或打印日志,或添加到 http 响应中,需要注意的是如果传入的 error 是空的话会引发 panic
元数据管理部分
也就是对于 Context 的 Keys 的操作接口,包括: Set
,Get
,MustGet
,GetString
,GetBool
,GetInt
,GetInt64
,GetFloat64
,GetTime
,GetDuration
,GetStringSlice
,GetStringMap
,GetStringMapString
,GetStringMapStringSlice
输入数据部分
也就是对URL Get 参数的处理
- Param: 获取 Context.Params 中的数据
- Query: 是
Context.Request.URL.Query().Get(key)
的快捷方式,获取 url 中的指定 key 的参数,不存在的话返回""
- DefaultQuery: 和 Query 类似,不过查询不到的话就返回传入的默认值
- GetQuery: 和 Query 类似,会返回查询是否成功
- QueryArray: 与 GetQueryArray 都是查询指定 key 返回一个 slice ,不同的是 GetQueryArray 会返回查询成功与否
- PostForm: 返回 POST 数据中的值,没有的话返回空字符串
("")
- DefaultPostForm: 传入默认值的获取方法
- GetPostForm: 和 PostForm 差不多,唯一不同的是会返回查询成功与否
- PostFormArray: 获取 POST 数据中对应 key 的字符串数组, GetPostFormArray 和 PostFormArray 其实调用的就是这个方法,不过忽略了他的查询是否成功
- FormFile: 返回对应表格 key 的第一个文件
- MultipartForm: 是解析过的 multipart form,包括上传的文件
- SaveUploadedFile: 将上上传的文件保存到指定位置
- Bind: 用于检查 Content-Type 然后自动选择一个绑定的引擎,比如:application/json 对应的 JSON 绑定, application/xml 对应 ** xml** 绑定;绑定不了的话会返回错误。然后会将传入的数据解析到指定的结构体指针中。如果输入不合法的话会写入400错误然后设置 Content-Type 为 plain/text
- BindJSON: 是 MustBindWith(obj,binding.JSON) 的快捷方式
- BindQuery: 是 MustBindWith(obj,bing.Query) 的快捷方式
- MustBindWith: 必需使用指定的绑定引擎来绑定传入的结构体指针,遇到任何问题会立刻返回 400 的 HTTP 错误码来中断请求
- ShouldBind: 与 Bind 功能一样,区别是此方法绑定的数据无效的时候不会推出也不会设置响应的错误为400
- ShouldBindJSON: 是 ShouldBindWith(obj, binding.JSON) 的快捷方式
- ShouldBindQuery: 是 ShouldBindWith(obj, binding.Query) 的快捷方式
- ShouldBindWith: 使用指定的绑定引擎绑定传入的结构体指针
- ClientIP: 使用最佳算法解析真实的客户端IP,通过解析 X-Real-IP 和 X-Forwarded-For 来与反转代理服务器,如 nginix , haproxy ,有效合作,由于 nginx 使用 X-Real-IP 作为代理 IP,所以会优先使用 X-Forwarded-IP
- ContentType: 返回请求头里面的
Content-Type
- IsWebsocket: 如果请求头里面有信息显示客户端已经发起来 websocket 握手请求,那么返回 true
- requestHeader: 私有方法,返回请求头里面的信息
响应渲染部分
- bodyAllowedForStatus: 是http.bodyAllowedForStatus 的不导出版本
- Status: 设置响应状态码
- Header: 添加或者设置响应头
- GetHeader: 返回指定的响应头值
- GetRawData: 返回响应体的流数据
- SetCookie: 在响应头里添加一个 Set-Cookie 的头信息。提供的 cookie 必需有一个有效的名字,无效的名字会静默去掉。
- Cookie: 返回请求里指定名字的 cookie ,找不到的时候返回 ErrNoCookie 。返回的 cookie 是 unescaped 。即使匹配到里多个 cookie ,最终他也只返回一个
- Render: 使用指定的渲染器和状态码来渲染响应数据
- HTML: HTMl 渲染指定文件名的 HTTP 模版,同时更新 HTTP 码,设置 Content-Type 为
text/html
- IndentedJSON: 将提供的结构体序列化为美化的 JSON 到响应体中,他会同时将 Content-Type 设置为
application/json
,官方在此警告,建议仅在开发中使用此功能,因为美化 JSON 会耗费更多的 CPU,传输过程中会耗费更多的带宽。 建议在生产环境中使用 Context.JSON() - SecureJSON: 将给定的结构体序列化为安全的 JSON 响应体中。如果给定的结构体是数组,那么默认会使用
while(1)
。同时他也会将 Content-Type 设置为application/json
- JSON: 将给定的结构体序列化为 JSON 到响应体。同时将 Content-Type 设置为
application/json
- XML: 将给定的结构体序列化为 XML 到响应体。同时将 Content-Type 设置为
application/xml
- YAML: 将给定的结构体序列化为 YAML 到响应体
- String: 将提供的字符串写入到响应体中
- Redirect: 重定向
- Data: 将数据写入响应流中,并更新 HTTP 码
- File: 高效的将指定的文件写入到响应流中
- SSEvent: 向响应流中写入一个 Server-Sent 事件
- Stream:
内容协定
此部分是关于 HTTP 接受内容的
GOLANG.ORG/X/NET/CONTEXT
此部分是 gin.Context 实现 golang.org/x/net/context
相关接口的