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的更多相关文章

  1. gin源码解读1-net/http的大概流程

    gin框架预览 router.Run()的源码: func (engine *Engine) Run(addr ...string) (err error) { defer func() { debu ...

  2. gin 源码阅读(1) - gin 与 net/http 的关系

    gin 是目前 Go 里面使用最广泛的框架之一了,弄清楚 gin 框架的原理,有助于我们更好的使用 gin. 这个系列 gin 源码阅读会逐步讲明白 gin 的原理. gin 概览 想弄清楚 gin, ...

  3. gin源码解读2-揭开gin的神秘面纱

    数据如何在gin中流转 func main() { gin.SetMode(gin.DebugMode) // 设置为开发模式 router := gin.Default() _ = router.S ...

  4. gin 源码阅读(2) - http请求是如何流入gin的?

    推荐阅读: gin 源码阅读(1) - gin 与 net/http 的关系 本篇文章是 gin 源码分析系列的第二篇,这篇文章我们主要弄清一个问题:一个请求通过 net/http 的 socket ...

  5. gin 源码阅读(5) - 灵活的返回值处理

    gin 源码阅读系列文章列表: gin 源码阅读(1) - gin 与 net/http 的关系 gin 源码阅读(2) - http请求是如何流入gin的? gin 源码阅读(3) - gin 路由 ...

  6. gin源码剖析

    介绍 Gin 是一个 Golang 写的 web 框架,具有高性能的优点,基于 httprouter,它提供了类似martini但更好性能(路由性能约快40倍)的API服务.官方地址:https:// ...

  7. Alamofire源码解读系列(二)之错误处理(AFError)

    本篇主要讲解Alamofire中错误的处理机制 前言 在开发中,往往最容易被忽略的内容就是对错误的处理.有经验的开发者,能够对自己写的每行代码负责,而且非常清楚自己写的代码在什么时候会出现异常,这样就 ...

  8. 源码解读·RT-Thread操作系统从开机到关机

    本篇内容比较简单,但却很繁琐,篇幅也很长,毕竟是囊括了整个操作系统的生命周期.这篇文章的目的是作为后续设计多任务开发的铺垫,后续会单独再抽出一篇分析任务的相关知识.另外本篇文章以单核MCU为背景,并且 ...

  9. HashTable、HashMap与ConCurrentHashMap源码解读

    HashMap 的数据结构 ​ hashMap 初始的数据结构如下图所示,内部维护一个数组,然后数组上维护一个单链表,有个形象的比喻就是想挂钩一样,数组脚标一样的,一个一个的节点往下挂. ​ 我们可以 ...

随机推荐

  1. Spring学习(一)idea中创建第一个Spring项目

    1.前言 Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container). Sprin ...

  2. 【LeetCode】520. Detect Capital 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 循环判断三个条件 大写字母个数和位置判断 根据首字符 ...

  3. 【kafka学习笔记】PHP接入kafka

    安装扩展 # 先安装rdkfka库文件 git clone https://github.com/edenhill/librdkafka.git 或者: wget https://gitee.com/ ...

  4. Second Order Optimization for Adversarial Robustness and Interpretability

    目录 概 主要内容 (4)式的求解 超参数 Tsiligkaridis T., Roberts J. Second Order Optimization for Adversarial Robustn ...

  5. ELK集中化日志解决方案——看这一篇全搞定

    一.前言 在软件发开技术管理里有两个永恒经典的问题,适合我们初到一家软件企业或一家公司的科技团队,来判断自己该从哪里入手帮助整个团队提升科技水平和产能.问题一是"在我们团队里,只涉及一行代码 ...

  6. vue 把字符串的所有=替换成&&&的方法

    //把字符串中所有=换成&&& let reg=new RegExp('=','g')//g代表全部 let newMsg=JSON.stringify(msg).replac ...

  7. IntelliJ IDEA 2019.3 代码提示忽略大小写(IDEA 2019版本如何设置代码提示不分大小写?)

    最近在使用IDEA,发现每次只能进行完全匹配,且区分大小写,界面变了IDEA 2019.3 忽略大小写设置跟之前的版本稍微有点不同,跟之前的软件有点点区别,在此记录一下不区分大小写的方法. 1. 使用 ...

  8. MySQL高级查询与编程笔记 • 【第4章 MySQL编程】

    全部章节   >>>> 本章目录 4.1 用户自定义变量 4.1.1 用户会话变量 4.1.2 用户会话变量赋值 4.1.3 重置命令结束标记 4.1.4 实践练习 4.2 存 ...

  9. 编写Java程序,实现一个简单的echo程序(网络编程TCP实践练习)

    首先启动服务端,客户端通过TCP的三次握手与服务端建立连接: 然后,客户端发送一段字符串,服务端收到字符串后,原封不动的发回给客户端. ECHO 程序是网络编程通信交互的一个经典案例,称为回应程序,即 ...

  10. 制造运营管理 (MOM) 的工作流驱动方法

    介绍 "在企业中使用的任何技术的第一条规则是,应用于高效运营的自动化将放大效率.第二个是自动化应用于低效率的操作会放大低效率." - 比尔盖茨 . 工作流是结构化的活动,主要涉及人 ...