【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…

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

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

rabbitMQ杂记

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

3.12 Bootstrap 超大屏幕(Jumbotron)

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

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

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

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

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

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

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

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

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

C# 抽象类和接口详解

参考视频链接:https://www.bilibili.com/video/BV13b411b7Ht?p27&vd_source10065785c7e10360d831474364e0d3e3 代码的进化与重构,从基本代码的讲解到逐步抽象成抽象类和接口。 文章目录 最初定义利用继承改进对方法进一步改进利用虚函数进行改进利…

如何设计光场2.0(聚焦型光场相机)系统参数

1. 系统参数设计 目前的硬件系统的现状:主透镜50mm,MLA:15*15,d0.5mm,f15mm,s4.8um 开普勒型光场系统: 首先我们需要确定系统的M,M参数表示单个位置的点能被多少个小微透镜成像&am…

python3GUI--仿win10任务管理器By:PyQt5(附UI源码)

文章目录 一.前言二.展示1.主界面1.进程2.性能1.CPU2.内存 3.简略信息4.详细信息5.新建任务 三.设计思路1.UI设计1.主界面1.进程2.性能3.详细信息4.新建任务5.图表信息组件 2.代码整体设计1.项目设计心得2.项目设计其他心得 3.其他心得 四&am…

Minecraft 1.20.x Forge模组开发 01.Idea开发环境配置

我们本次来进行Minecraft 1.20.x 模组开发环境配置教程的介绍。 效果演示 效果演示 效果演示 1.首先我们需要下载Java17和1.20模组开发包: Java17下载官网

智安网络|保护数据资产:不同行业下的数据安全建设策略

在当今数字化时代,数据安全已经成为各行各业无法忽视的重要议题。保持良好网络卫生习惯并及时了解不断变化的网络威胁是企业中每个人的责任。企业、政府机构、医疗机构、金融机构以及其他组织和行业都面临着日益复杂和频繁的网络安全威胁。为了有效应对这些威胁&…

JVM系统优化实践(20):GC生产环境案例(三)

您好,这里是「码农镖局」CSDN博客,欢迎您来,欢迎您再来~ 某新手开发工程师接到了一个保存Elasticsearch日志的任务,以供后续分析之用。但写代码的时候,误将保存日志的代码段弄成了无限循环,程序…

面试题 02.07. 链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后&#x…

24 MFC文档串行化和单文档应用程序

文章目录 文档串行化全部代码 单文档应用程序搭建原理搭建框架Win32 过度到MFC 三部曲设置ID资源全部代码 单文档应用程序设置标题绘图 简单的管理系统部分代码 文档串行化 ui 设计 保存 void CfileDemoDlg::OnBnClickedBtnSave() {UpdateData();//CFile file(L"Demo.dat…