gin源码解读3-gin牛逼的context
Gin封装的最好的地方就是context和对response的处理. github的README的介绍,基本就是对这两个东西的解释. 本篇文章主要解释context的使用方法, 以及其设计原理
为什么要将Request的处理封装到Context中
在阅读gin的源码时, 请求的处理是使用type HandlerFunc func(*Context)来处理的. 也就是
func(context *gin.Context) {
context.String(http.StatusOK, "some post")
}
参数是gin.Context, 但是查看源码发现其实gin.Context在整个框架处理的地方只有下面这段:
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset()
engine.handleHTTPRequest(c)
engine.pool.Put(c)
}
那为什么还要利用Context来处理呢. gin的context实现了的context.Context Interface.
经过查看context.Context相关资料, Context的最佳运用场景就是对Http的处理. 封装成Conetxt另外的好处就是WithCancel, WithDeadline, WithTimeout, WithValue这些context包衍生的子Context就可以直接来使用.
gin.Context设计
这个模块比较简单, 就是从gin.Context中Set Key-Value, 以及各种个样的Get方法, 如GetBool, GetString等
实现这些功能也很简单, 其实就是一个map
// Keys is a key/value pair exclusively for the context of each request.
Keys map[string]interface{}
Input Data
这个模块相当重要了, gin的README基本上都在介绍这个模块的用法.
Param (我自己的叫法: 路由变量)
gin的标准叫法是Parameters in path. restful风格api如/user/john, 这个路由在gin里面是/user/:name, 要获取john就需要使用Param函数
name := context.Param("name")
这个方法实现也很简单, 就是在tree.go里面根据路由相关规则解析出来然后赋值给gin.Context的Params.
Query
/welcome?firstname=Jane&lastname=Doe这样一个路由, first, last即是Querystring parameters, 要获取他们就需要使用Query相关函数.
c.Query("first") // Jane
c.Query("last") // Doe
当然还有其他相关函数:
QueryMap
DefaultQuery 这个默认值的实现更加简单, 当QueryString中不包含这个值, 直接返回填入的值
这些方法是的实现是利用net/http的Request的方法实现的
PostForm
FormFile
对于文件相关的操作, 一般生产情况下不建议这样使用, 因为把文件上传到服务器磁盘, 还得磁盘相关的监控. 我觉得最好利用云服务商相关的对象存储, 如:阿里云OSS, 七牛云对象存储, AWS的对象存储等来做文件的相关操作
Bind
内置的有json, xml, protobuf, form, query, yaml. 这些Bind极大的减少我们自己去解析各种个样的数据格式, 提高我们的开发速度
Bind的实现都在gin/binding里面. 这些内置的Bind都实现了Binding接口, 主要是Bind()函数.
context.BindJSON() 支持MIME为application/json的解析
context.BindXML() 支持MIME为application/xml的解析
context.BindYAML() 支持MIME为application/x-yaml的解析
context.BindQuery() 只支持QueryString的解析, 和Query()函数一样
context.BindUri() 只支持路由变量的解析
Context.Bind() 支持所有的类型的解析, 这个函数尽量还是少用(当QueryString, PostForm, 路由变量在一块同时使用时会产生意想不到的效果), 目前测试Bind不支持路由变量的解析, Bind()函数的解析比较复杂, 这部分代码后面再看
Response
对Header的支持
- Header
- GetHeader
这里的Header是写到Response里面的Header. 对于客户端发的请求的Header可以通过context.Request.Header.Get("Content-Type")获取
context.Header("jwt", "123456") // 写到Response的Header
clientIp := context.GetHeader("X-Forwarded-For") // 从Request中获取Header
fmt.Println(clientIp)
Cookie
提供对session, cookie的支持
[cookie和session](https://www.cnblogs.com/mayanan/p/15672208.html)
render
做api常用到的其实就是gin封装的各种render. 目前支持的有:
func (c *Context) JSON(code int, obj interface{})
func (c *Context) Protobuf(code int, obj interface{})
func (c *Context) YAML(code int, obj interface{}) ...
当然我们可以自定义渲染, 只要实现func (c *Context) Render(code int, r render.Render)即可.
这里我们常用的是一个方法是: gin.H{"error": 111}. 这个结构相当实用, 各种render都支持. 其实这个结构很简单就是type H map[string]interface{}, 当我们要从map转换各种各样结构时, 不妨参考gin这里的代码
Context说到这里基本就说完了, 这里介绍的方法都是开发中特别实用的方法. context的代码实现也特别有条理, 建议可以看看这部分代码
gin源码解读3-gin牛逼的context的更多相关文章
- gin源码解读1-net/http的大概流程
gin框架预览 router.Run()的源码: func (engine *Engine) Run(addr ...string) (err error) { defer func() { debu ...
- gin 源码阅读(1) - gin 与 net/http 的关系
gin 是目前 Go 里面使用最广泛的框架之一了,弄清楚 gin 框架的原理,有助于我们更好的使用 gin. 这个系列 gin 源码阅读会逐步讲明白 gin 的原理. gin 概览 想弄清楚 gin, ...
- gin源码解读2-揭开gin的神秘面纱
数据如何在gin中流转 func main() { gin.SetMode(gin.DebugMode) // 设置为开发模式 router := gin.Default() _ = router.S ...
- gin 源码阅读(2) - http请求是如何流入gin的?
推荐阅读: gin 源码阅读(1) - gin 与 net/http 的关系 本篇文章是 gin 源码分析系列的第二篇,这篇文章我们主要弄清一个问题:一个请求通过 net/http 的 socket ...
- gin 源码阅读(5) - 灵活的返回值处理
gin 源码阅读系列文章列表: gin 源码阅读(1) - gin 与 net/http 的关系 gin 源码阅读(2) - http请求是如何流入gin的? gin 源码阅读(3) - gin 路由 ...
- gin源码剖析
介绍 Gin 是一个 Golang 写的 web 框架,具有高性能的优点,基于 httprouter,它提供了类似martini但更好性能(路由性能约快40倍)的API服务.官方地址:https:// ...
- Alamofire源码解读系列(二)之错误处理(AFError)
本篇主要讲解Alamofire中错误的处理机制 前言 在开发中,往往最容易被忽略的内容就是对错误的处理.有经验的开发者,能够对自己写的每行代码负责,而且非常清楚自己写的代码在什么时候会出现异常,这样就 ...
- 源码解读·RT-Thread操作系统从开机到关机
本篇内容比较简单,但却很繁琐,篇幅也很长,毕竟是囊括了整个操作系统的生命周期.这篇文章的目的是作为后续设计多任务开发的铺垫,后续会单独再抽出一篇分析任务的相关知识.另外本篇文章以单核MCU为背景,并且 ...
- HashTable、HashMap与ConCurrentHashMap源码解读
HashMap 的数据结构 hashMap 初始的数据结构如下图所示,内部维护一个数组,然后数组上维护一个单链表,有个形象的比喻就是想挂钩一样,数组脚标一样的,一个一个的节点往下挂. 我们可以 ...
随机推荐
- Spring学习(一)idea中创建第一个Spring项目
1.前言 Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container). Sprin ...
- 【LeetCode】520. Detect Capital 解题报告(Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 循环判断三个条件 大写字母个数和位置判断 根据首字符 ...
- 【kafka学习笔记】PHP接入kafka
安装扩展 # 先安装rdkfka库文件 git clone https://github.com/edenhill/librdkafka.git 或者: wget https://gitee.com/ ...
- Second Order Optimization for Adversarial Robustness and Interpretability
目录 概 主要内容 (4)式的求解 超参数 Tsiligkaridis T., Roberts J. Second Order Optimization for Adversarial Robustn ...
- ELK集中化日志解决方案——看这一篇全搞定
一.前言 在软件发开技术管理里有两个永恒经典的问题,适合我们初到一家软件企业或一家公司的科技团队,来判断自己该从哪里入手帮助整个团队提升科技水平和产能.问题一是"在我们团队里,只涉及一行代码 ...
- vue 把字符串的所有=替换成&&&的方法
//把字符串中所有=换成&&& let reg=new RegExp('=','g')//g代表全部 let newMsg=JSON.stringify(msg).replac ...
- IntelliJ IDEA 2019.3 代码提示忽略大小写(IDEA 2019版本如何设置代码提示不分大小写?)
最近在使用IDEA,发现每次只能进行完全匹配,且区分大小写,界面变了IDEA 2019.3 忽略大小写设置跟之前的版本稍微有点不同,跟之前的软件有点点区别,在此记录一下不区分大小写的方法. 1. 使用 ...
- MySQL高级查询与编程笔记 • 【第4章 MySQL编程】
全部章节 >>>> 本章目录 4.1 用户自定义变量 4.1.1 用户会话变量 4.1.2 用户会话变量赋值 4.1.3 重置命令结束标记 4.1.4 实践练习 4.2 存 ...
- 编写Java程序,实现一个简单的echo程序(网络编程TCP实践练习)
首先启动服务端,客户端通过TCP的三次握手与服务端建立连接: 然后,客户端发送一段字符串,服务端收到字符串后,原封不动的发回给客户端. ECHO 程序是网络编程通信交互的一个经典案例,称为回应程序,即 ...
- 制造运营管理 (MOM) 的工作流驱动方法
介绍 "在企业中使用的任何技术的第一条规则是,应用于高效运营的自动化将放大效率.第二个是自动化应用于低效率的操作会放大低效率." - 比尔盖茨 . 工作流是结构化的活动,主要涉及人 ...