【golang】12、gin 源码解析

在这里插入图片描述

文章目录

  • 快速使用
  • 返回响应
  • 路由匹配
    • path
    • query
    • Multipart/Urlencoded Form
  • 解析请求
    • MultipartFrom
  • MiddleWare

github.com/gin-gonic/gin 是 golang 的 web 框架,其用字典树做路由匹配、支持中间件,本文介绍其源码实现。

快速使用

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "pong",})})r.Run()
}// curl localhost:8000/ping 则返回 PONG

默认使用 encoding/json 库,当 go build -tags=jsoniter . 时会用 github.com/json-iterator/go 库。

在 Gin examples repository 可以找到官方使用示例。

返回响应

func Error500(ctx *gin.Context, err error) {ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
}func Error400(ctx *gin.Context, err error) {ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
}

路由匹配

path

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {router := gin.Default()// 可以用:匹配路径 This handler will match /user/john or /user/ but will not match /userrouter.GET("/user/:name", func(c *gin.Context) {name := c.Param("name")c.String(http.StatusOK, "Hello %s", name)})// 可以用:匹配路径,可以用*做可选路径匹配(匹配的结果带/) However, this one will match /user/john/ and also /user/john/send If no other routers match /user/john, it will redirect to /user/john/router.GET("/user/:name/*action", func(c *gin.Context) {name := c.Param("name")action := c.Param("action")message := name + " is " + actionc.String(http.StatusOK, message)}) 可以用完整路径匹配 For each matched request Context will hold the route definitionrouter.POST("/user/:name/*action", func(c *gin.Context) {b := c.FullPath() == "/user/:name/*action" // truec.String(http.StatusOK, "%t, %v", b, c.FullPath())})// 如果没有:或*	则表示路由组,可保证路由树解析优先级高于:路径匹配// This handler will add a new router for /user/groups.// Exact routes are resolved before param routes, regardless of the order they were defined.// Routes starting with /user/groups are never interpreted as /user/:name/... routesrouter.GET("/user/groups", func(c *gin.Context) {c.String(http.StatusOK, "The available groups are [...]")})router.Run(":8080")
}

可以用*来匹配变长 url,例如需求为(定义了一个路由 /a/:name/d ,真实请求的url为 /a/b/c/d ,怎么能让参数name匹配成 b/c),示例如下:
在这里插入图片描述

query

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {router := gin.Default()// Query string parameters are parsed using the existing underlying request object.// The request responds to an url matching:  /welcome?firstname=Jane&lastname=Doerouter.GET("/welcome", func(c *gin.Context) {firstname := c.DefaultQuery("firstname", "Guest")lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")c.String(http.StatusOK, "Hello %s %s", firstname, lastname)})router.Run(":8080")
}

Multipart/Urlencoded Form

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {router := gin.Default()router.POST("/form_post", func(c *gin.Context) {message := c.PostForm("message")nick := c.DefaultPostForm("nick", "anonymous")c.JSON(http.StatusOK, gin.H{"status":  "posted","message": message,"nick":    nick,})})router.Run(":8080")
}

在这里插入图片描述

解析请求

MultipartFrom

// ParseMultipartForm 解析 multipart/form-data 类型的 Content-Type,其将收到的文件先存储在内存中,若超限则存储在磁盘中
// ParseMultipartForm parses a request body as multipart/form-data.
// The whole request body is parsed and up to a total of maxMemory bytes of
// its file parts are stored in memory, with the remainder stored on
// disk in temporary files.
// ParseMultipartForm calls ParseForm if necessary.
// If ParseForm returns an error, ParseMultipartForm returns it but also
// continues parsing the request body.
// After one call to ParseMultipartForm, subsequent calls have no effect.
func (r *Request) ParseMultipartForm(maxMemory int64) error {if r.MultipartForm == multipartByReader {return errors.New("http: multipart handled by MultipartReader")}var parseFormErr errorif r.Form == nil {// Let errors in ParseForm fall through, and just// return it at the end.parseFormErr = r.ParseForm()}if r.MultipartForm != nil {return nil}mr, err := r.multipartReader(false)if err != nil {return err}f, err := mr.ReadForm(maxMemory)if err != nil {return err}if r.PostForm == nil {r.PostForm = make(url.Values)}for k, v := range f.Value {r.Form[k] = append(r.Form[k], v...)// r.PostForm should also be populated. See Issue 9305.r.PostForm[k] = append(r.PostForm[k], v...)}r.MultipartForm = freturn parseFormErr
}

用 postman 传递的方式如下:
在这里插入图片描述

在 gin 解析参数时,可用 multipartForm.Value["k"] 方式接收,得到 []string
在这里插入图片描述
解析的参数定义如下:

// Form is a parsed multipart form.
// Its File parts are stored either in memory or on disk,
// and are accessible via the *FileHeader's Open method.
// Its Value parts are stored as strings.
// Both are keyed by field name.
type Form struct {Value map[string][]stringFile  map[string][]*FileHeader
}// A FileHeader describes a file part of a multipart request.
type FileHeader struct {Filename stringHeader   textproto.MIMEHeaderSize     int64content []bytetmpfile string
}

MiddleWare

gin 的 middleware 和 处理函数,都是 HandlerFunc 类型。

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)// HandlersChain defines a HandlerFunc slice.
type HandlersChain []HandlerFunc

gin 有各种中间件,是通过数组实现的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/4462.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ylb-接口6验证手机号是否注册

总览: 1、service处理 在api模块下service包,创建一个UserService接口:(根据手机号查询数据queryByPhone(String phone)) package com.bjpowernode.api.service;import com.bjpowernode.api.model.User; import co…

ASL/CS系列音视频转换方案芯片,Typec拓展坞方案芯片

音视频单转方案芯片: CS5565 Typec转HDMI 8K 60HZ转换方案 可替代RTD2173 PS196 CS5801 HDMI转eDP/DP方案 可替代LT6711 CS5212 DP转VGA转换方案 可PIN TO PIN 替代RTD2166 CS5211 E…

❤️创意网页:HTML5 Canvas技术实现绚丽多彩的烟花特效

✨博主:命运之光 🌸专栏:Python星辰秘典 🐳专栏:web开发(简单好用又好看) ❤️专栏:Java经典程序设计 ☀️博主的其他文章:点击进入博主的主页 前言:欢迎踏入…

【java】【基础2】程序流程控制

目录 一、最经典的三种执行顺序 二、分支结构 2.1 if 2.2 switch 2.3 if与switch区别 三、循环结构 3.1 for循环 3.2 while循环 3.3 do-while循环 3.4 三种循环区别 3.5 补充知识:死循环 3.6 补充知识:循环嵌套 四、跳转关键字:br…

Mysql如何查询出两个日期之间的所有日期?

问题: 有时我们在生成一些时间轴类似的数据时,要求数据库不管有没有指定天的数据,都要生成该时间节点,可用mysql.help_topic来解决此类问题,通过序列和日期函数相结合来满足我们的业务需求。 例如:查询20…

spring启动一下就停止了

spring启动一下就停止了。 这个问题比较简单,百度了下,还是有些人问,记录下吧。 是因为没有引入spring-boot-starter-web包,或者该包没有生效。 有时spring-boot-starter-parent版本不对,就可能没生效,写明…

LeetCode | C++ 动态规划——123.买卖股票的最佳时机III 、188.买卖股票的最佳时机IV

目录 123.买卖股票的最佳时机III188.买卖股票的最佳时机IV 123.买卖股票的最佳时机III 123题目链接 根据题意:最多可以完成 两笔 交易,即可以买卖股票一次,可以买卖两次,也可以不买卖 dp数组定义: 此时 一天就有五个…

Web开发的富文本编辑器CKEditor介绍,Django有库ckeditor_uploader对它进行支持,django-ckeditor安装方法及使用注意事项

当需要在网页应用程序中提供富文本编辑功能时,CKEditor是一个流行的选择。CKEditor是一个开源的JavaScript富文本编辑器,它提供了强大的功能和用户友好的界面,使用户可以轻松创建和编辑格式化的文本内容。 以下是CKEditor的一些主要特性&…

kakfa 2.4.1 java的生产者client在发送消息前分配消息属于哪个分区源码

标题是否不是很熟悉,面试不得必问啊 KafkaProducer 1、客户端暴露出来可以让开发人员调用的发送消息的方法send2、send实际调用私有方法doSend获取集群信息(并且得到这条数据写哪个分区)2.1获取kafka服务端集群某个topic的元数据方法waitOnMetadata2.2根据消息是否指…

rabbitMQ杂记

消息队列应用场景 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量 削锋等问题实现高性能,高可用,可伸缩和最终一致性: 解耦: 异步: 削峰: 常…

再见RestTemplate,Spring 6.1新特性:RestClient 了解一下!

在最近发布的Spring 6.1 M2版本中,推出了一个全新的同步HTTP客户端:RestClient。用一句话来让Spring开发者认识RestClient的话:像WebClient一样具备流畅API的RestTemplate。 所以,RestClient的使命就是淘汰已经有14年历史的RestTe…

实习经历总结

写在前面: 临毕业前突发奇想打算找实习,由于准备不是很充分加上没有经验,海投了一些岗位,方向主要是测试开发,base主要是北京&天津。 一些公司的面试: 当时投了很多大厂,美团&#xff0c…

elasticsearch高级功能之跨集群复制CCR

CCR的作用(Cross-Cluster Replication,跨集群复制)常用的场景如何使用工作原理源码分析 CCR的作用(Cross-Cluster Replication,跨集群复制) CCR功能允许用户在不同的Elasticsearch集群之间同步索引数据。这对于实现跨集群复制、数据备份、灾难恢复和多数…

3.12 Bootstrap 超大屏幕(Jumbotron)

文章目录 Bootstrap 超大屏幕(Jumbotron) Bootstrap 超大屏幕(Jumbotron) 下面将讲解 Bootstrap 支持的另一个特性,超大屏幕(Jumbotron)。顾名思义该组件可以增加标题的大小,并为登陆…

详解Windows安装分布式版本控制系统git

文章目录 前言下载安装相关链接 前言 git是一个分布式版本控制软件,最初由Linux创作者Linus Torvalds创作,并于2015年以GPL许可协议发布。git易于学习,占用空间小,性能却快如闪电,可以快速、 高效的管理从小到大的项目…

uniapp-轮播图swiper根据内容图片高度自适应,解决获取图片高度不准确的问题

需求:轮播图swiper根据内容图片高度自适应 但是通过uniapp uni.createSelectorQuery的方法获取图片高度不正确,比如图片是100,获取是200,this.$nextTick也不能解决,setTimeout到是能解决,但是不稳定&#…

DeFi新篇章 | Sui上原生订单簿DeepBook正式上线

随着原生去中心化中央限价订单簿( Central Limit Order Book,CLOB)DeepBook的推出,Sui上的DeFi开启了新篇章。DeepBook由一群Sui贡献者共同构建,为新一代DeFi应用提供了一个稳定的流动性层。 通过DeepBook&#xff0c…

Kubernetes在数字化转型中的作用

Kubernetes在数字化转型中的作用 数字化转型是指在现代化社会中,利用数字技术来改变企业、组织或个人的业务模式、流程和价值创造方式的过程。这包括使用数字技术来提高效率、创新产品或服务、优化客户体验和开发新的业务模式等方面。数字化转型是一个全球性的趋势…

mac批量修改文件名为不同名字

mac批量修改文件名为不同名字怎么弄?很多小伙伴通过私信向我求助,用什么方法可以在mac电脑上批量修改文件名称,将大量文件修改成不同的名称。这可能是一项比较麻烦的操作,在电脑上进行过批量重命名的小伙伴都知道,一般…

Redis源码篇 - Reactor设计模式 和 Redis Reactor设计模式

Reactor :反应器模式或者应答者模式,它是一种基于事件驱动的设计模式。拥有一个或者多个输入源,通过反应器分发给多个worker线程处理,实现并发场景下事件处理。 此图网上找的,画的很好: