【Go学习】04-1-Gin框架-路由请求响应参数

【Go学习】04-1-Gin框架

  • 初识框架
    • go流行的web框架
      • Gin
      • iris
      • Beego
      • fiber
    • Gin介绍
    • Gin快速入门
  • 路由
    • RESTful API规范
    • 请求方法
    • URI
      • 静态url
      • 路径参数
      • 模糊匹配
    • 处理函数
    • 分组路由
  • 请求参数
    • GET请求参数
      • 普通参数
      • 数组参数
      • map参数
    • POST请求参数
      • 表单参数
      • JSON参数
    • 路径参数
    • 文件参数
  • 响应
    • 字符串方式
    • JSON方式
    • XML方式
    • 文件方式
    • 设置http响应头
    • 重定向
    • YAML方式


初识框架

框架是一系列工具的集合,能让开发变的便捷。

学习框架的目的就是为了提供项目的开发效率,使我们更加专注业务,而不是和业务无关的底层代码。

go流行的web框架

如果学习过其他语言,可能知道Java用的比较多的是Spring框架,PHP用的比较多的是Laravel,python用的多的是Django,都在各自的语言中具有强大的统治力。

go从诞生之初就带有浓重的开源属性,其原生库已经很强大,即使不依赖框架,也能进行高性能开发,又因为其语言并没有一定的设计标准,所以较为灵活,也就诞生了众多的框架,各具有特色,满足不同的喜好。

Gin

地址:https://github.com/gin-gonic/gin

号称最快的go语言web框架,目前是go官方的推荐框架(https://go.dev/doc/tutorial/)。

iris

地址:https://github.com/kataras/iris

性能比gin高一些,支持MVC,但这款框架评价不太好,使用上问题较多,近些年很少去选择使用

Beego

地址:https://github.com/beego/beego

国人开发,最早的go web框架之一,工具集比较完善,性能较差,据传言作者是php转行,所以框架带有浓厚的php特色,早期国内使用的多,目前少有人选择。

fiber

地址:https://github.com/gofiber/fiber

2020年发布的框架,发展迅速,建立在fasthttp之上,性能目前最高,受Express启发,比较简洁,上手较快,和gin类似。

当然还有其他一些框架,但从star数上,以及流行程度上看,gin一骑绝尘,gin的好处在于其简洁,扩展性,稳定性以及性能都比较出色。

go的框架其实是可以理解为库,并不是用了某一个框架就不能用别的框架,可以选择性的使用各个库中的优秀组件,进行组合

Gin介绍

特性:

  • 快速

    基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。

  • 支持中间件

    传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。

  • Crash 处理

    Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic!

  • JSON 验证

    Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。

  • 路由组

    更好地组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。

  • 错误管理

    Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。

  • 内置渲染

    Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。

  • 可扩展性

    新建一个中间件非常简单。

Gin快速入门

go版本需求:go1.13及以上

环境:windows 11

# 创建工作区
F:\Code\Golang\TuLing\workPath>mkdir ginlearn
F:\Code\Golang\TuLing\workPath>cd ginlearn
# 初始化工作区
F:\Code\Golang\TuLing\workPath\ginlearn>go work init# 创建模块
F:\Code\Golang\TuLing\workPath\ginlearn>mkdir helloworld
F:\Code\Golang\TuLing\workPath\ginlearn>cd helloworld
# 初始化模块
F:\Code\Golang\TuLing\workPath\ginlearn\helloworld>go mod init test.com/helloworld
go: creating new go.mod: module test.com/helloworld
F:\Code\Golang\TuLing\workPath\ginlearn\helloworld>cd ..# 将模块加入工作区
F:\Code\Golang\TuLing\workPath\ginlearn>go work use ./helloworld

使用goland打开

在这里插入图片描述

下载gin

PS F:\Code\Golang\TuLing\workPath\ginlearn> cd .\helloworld\
PS F:\Code\Golang\TuLing\workPath\ginlearn\helloworld> go get -u github.com/gin-gonic/gin

示例程序,创建main.go

package mainimport "github.com/gin-gonic/gin"func main() {r := gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

运行后,apifox进行测试

在这里插入图片描述

符合预期,这样简单的代码就实现了一个http的服务

路由

路由是URI到函数的映射。

一个URI含: http://localhost:8080/user/find?id=11

  • 协议,比如http,https等
  • ip端口或者域名,比如127.0.0.1:8080或者www.test.com
  • path,比如 /path
  • query,比如 ?query

同时访问的时候,还需要指明HTTP METHOD,比如

  • GET

    GET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据.

  • POST

    POST方法用于将实体提交到指定的资源,通常会导致在服务器上的状态变化

  • HEAD

    HEAD方法请求一个与GET请求的响应相同的响应,但没有响应体.

  • PUT

    PUT方法用请求有效载荷替换目标资源的所有当前表示

  • DELETE

    DELETE方法删除指定的资源

  • CONNECT

    CONNECT方法建立一个到由目标资源标识的服务器的隧道。

  • OPTIONS

    OPTIONS方法用于描述目标资源的通信选项。

  • TRACE

    TRACE方法沿着到目标资源的路径执行一个消息环回测试。

  • PATCH

    PATCH方法用于对资源应用部分修改。

使用的时候,应该尽量遵循其语义

RESTful API规范

RESTful API 的规范建议我们使用特定的HTTP方法来对服务器上的资源进行操作。

比如:

  1. GET,表示读取服务器上的资源
  2. POST,表示在服务器上创建资源
  3. PUT,表示更新或者替换服务器上的资源
  4. DELETE,表示删除服务器上的资源
  5. PATCH,表示更新/修改资源的一部分

请求方法

r.GET("/get", func(ctx *gin.Context) {ctx.JSON(200, "get")
})
r.POST("/post", func(ctx *gin.Context) {ctx.JSON(200, "post")
})
r.DELETE("/delete", func(ctx *gin.Context) {ctx.JSON(200, "delete")
})
r.PUT("/put", func(ctx *gin.Context) {ctx.JSON(200, "put")
})

如果想要支持所有:

r.Any("/any", func(ctx *gin.Context) {ctx.JSON(200, "any")
})

如果想要支持其中的几种:

r.GET("/hello", func(ctx *gin.Context) {//数组 map list 结构体ctx.JSON(200, gin.H{"name": "hello world",})
})
r.POST("/hello", func(ctx *gin.Context) {//数组 map list 结构体ctx.JSON(200, gin.H{"name": "hello world",})
})

URI

URI书写的时候,我们不需要关心scheme和authority这两部分,我们主要通过path和query两部分的书写来进行资源的定位。

静态url

比如/hello/user/find

r.POST("/user/find", func(ctx *gin.Context) {
})

路径参数

比如/user/find/:id

r.POST("/user/find/:id", func(ctx *gin.Context) {param := ctx.Param("id")ctx.JSON(200, param)
})

模糊匹配

比如/user/*path

r.POST("/user/*path", func(ctx *gin.Context) {param := ctx.Param("path")ctx.JSON(200, param)
})

处理函数

定义:

type HandlerFunc func(*Context)

通过上下文的参数,获取http的请求参数,响应http请求等。

分组路由

在进行开发的时候,我们往往要进行模块的划分,比如用户模块,以user开发,商品模块,以goods开头。

或者进行多版本开发,不同版本之间路径是一致的,这种时候,就可以用到分组路由了。

比如

ug := r.Group("/user")
{ug.GET("find", func(ctx *gin.Context) {ctx.JSON(200, "user find")})ug.POST("save", func(ctx *gin.Context) {ctx.JSON(200, "user save")})
}
gg := r.Group("/goods")
{gg.GET("find", func(ctx *gin.Context) {ctx.JSON(200, "goods find")})gg.POST("save", func(ctx *gin.Context) {ctx.JSON(200, "goods save")})
}

请求路径则为

[GIN-debug] GET    /user/find                --> main.main.func2 (3 handlers)
[GIN-debug] POST   /user/save                --> main.main.func3 (3 handlers)
[GIN-debug] GET    /goods/find               --> main.main.func4 (3 handlers)
[GIN-debug] POST   /goods/save               --> main.main.func5 (3 handlers)

请求参数

GET请求参数

使用Get请求传参时,类似于这样

http://localhost:8080/user/save?id=11&name=zhangsan

如何获取呢?

普通参数

request url: http://localhost:8080/user/save?id=11&name=zhangsan

  • Query:匹配字段

    r.GET("/user/save", func(ctx *gin.Context) {id := ctx.Query("id")name := ctx.Query("name")ctx.JSON(200, gin.H{"id":   id,"name": name,})
    })
    

    如果参数不存在,就给一个默认值:

  • DefaultQuery:query为空时回返回个默认值

    r.GET("/user/save", func(ctx *gin.Context) {id := ctx.Query("id")name := ctx.Query("name")address := ctx.DefaultQuery("address", "北京")ctx.JSON(200, gin.H{"id":      id,"name":    name,"address": address,})
    })
    
  • GetQuery:多了个query成功与否的返回值

    r.GET("/user/save", func(ctx *gin.Context) {id, ok := ctx.GetQuery("id")address, aok := ctx.GetQuery("address")ctx.JSON(200, gin.H{"id":      id,"idok":    ok,"address": address,"aok":     aok,})
    })
    

    id是数值类型,上述获取的都是string类型,根据类型获取:通过form进行字段匹配

  • BindQuery:与结构体字段进行匹配

    type User struct {Id   int64  `form:"id"`Name string `form:"name"`
    }
    r.GET("/user/save", func(ctx *gin.Context) {var user Usererr := ctx.BindQuery(&user)if err != nil {log.Println(err)}ctx.JSON(200, user)
    })
    
  • ShouldBindQuery:有binding字段的要求必填,否则报错

    r.GET("/user/save", func(ctx *gin.Context) {var user Usererr := ctx.ShouldBindQuery(&user)if err != nil {log.Println(err)}ctx.JSON(200, user)
    })
    

    区别

    当bind是必须的时候,ShouldBindQuery会报错,开发者自行处理,状态码不变。

    type User struct {Id      int64  `form:"id"`Name    string `form:"name"`Address string `form:"address" binding:"required"`
    }
    

    BindQuery则报错的同时,会将状态码改为400。所以一般建议是使用Should开头的bind。

数组参数

请求url:http://localhost:8080/user/save?address=Beijing&address=shanghai

  • QueryArray:重复查询字段组装成数组

    r.GET("/user/save", func(ctx *gin.Context) {address := ctx.QueryArray("address")ctx.JSON(200, address)
    })
    
  • GetQueryArray:多成功与否返回值

    r.GET("/user/save", func(ctx *gin.Context) {address, ok := ctx.GetQueryArray("address")fmt.Println(ok)ctx.JSON(200, address)
    })
    
  • ShouldBindQuery

    r.GET("/user/save", func(ctx *gin.Context) {var user Usererr := ctx.ShouldBindQuery(&user)fmt.Println(err)ctx.JSON(200, user)
    })
    

    但是这样的话我们的user的address要求就是个数组

    type User struct {Id      int64    `form:"id"`Name    string   `form:"name"`Address []string `form:"address" binding:"required"`
    }
    

    成功返回

    {"Id": 0,"Name": "","Address": ["Beijing","shanghai"]
    }
    

map参数

请求url:http://localhost:8080/user/save?addressMap[home]=Beijing&addressMap[company]=shanghai

  • QueryMap:组装成map

    r.GET("/user/save", func(ctx *gin.Context) {addressMap := ctx.QueryMap("addressMap")ctx.JSON(200, addressMap)
    })
    
  • GetQueryMap:多成功与否返回值

    r.GET("/user/save", func(ctx *gin.Context) {addressMap, _ := ctx.GetQueryMap("addressMap")ctx.JSON(200, addressMap)
    })
    

    返回值

    {"company": "shanghai","home": "Beijing"
    }
    

POST请求参数

post请求一般是表单参数和json参数

表单参数

r.POST("/user/save", func(ctx *gin.Context) {id := ctx.PostForm("id")name := ctx.PostForm("name")address := ctx.PostFormArray("address")addressMap := ctx.PostFormMap("addressMap")ctx.JSON(200, gin.H{"id":         id,"name":       name,"address":    address,"addressMap": addressMap,})
})
  • PostForm:从表单中对应的字段
  • PostFormArray:从表单找对应的数组
  • PostFormMap:从表单找对应的Map
r.POST("/user/save", func(ctx *gin.Context) {var user Usererr := ctx.ShouldBind(&user)addressMap, _ := ctx.GetPostFormMap("addressMap")user.AddressMap = addressMapfmt.Println(err)ctx.JSON(200, user)
})
  • GetPostFormMap:从表单找对应的Map

JSON参数

json参数如下

{"id":1111,"name":"zhangsan","address": ["beijing","shanghai"],"addressMap":{"home":"beijing"}
}
r.POST("/user/save", func(ctx *gin.Context) {var user Usererr := ctx.ShouldBindJSON(&user)fmt.Println(err)ctx.JSON(200, user)
})

对应字段进行匹配

其他类型参数注入xml,yaml等和json道理一样

路径参数

请求url:http://localhost:8080/user/save/111

r.POST("/user/save/:id", func(ctx *gin.Context) {ctx.JSON(200, ctx.Param("id"))
})
  • :id 表示 占位符,可以匹配 任意路径中的值

  • ctx.Param("id") 用于 获取路径参数 id 的值

文件参数

r.POST("/user/save", func(ctx *gin.Context) {form, err := ctx.MultipartForm()if err != nil {log.Println(err)}files := form.Filefor _, fileArray := range files {for _, v := range fileArray {ctx.SaveUploadedFile(v, "./"+v.Filename)}}ctx.JSON(200, form.Value)
})

在form表单中请求file类型

在这里插入图片描述

这样就能在本地看到了

在这里插入图片描述

响应

字符串方式

r.GET("/user/save", func(ctx *gin.Context) {ctx.String(http.StatusOK, "this is a %s", "ms string response")
})

JSON方式

r.GET("/user/save", func(ctx *gin.Context) {ctx.JSON(http.StatusOK, gin.H{"success": true,})
})

XML方式

r.GET("/user/save", func(ctx *gin.Context) {u := XmlUser{Id:   11,Name: "zhangsan",}ctx.XML(http.StatusOK, u)
})

文件方式

r.GET("/user/save", func(ctx *gin.Context) {//ctx.File("./1.png")ctx.FileAttachment("./1.png", "2.png")
})

设置http响应头

r.GET("/user/save", func(ctx *gin.Context) {ctx.Header("test", "headertest")
})

重定向

r.GET("/user/save", func(ctx *gin.Context) {ctx.Redirect(http.StatusMovedPermanently, "http://www.baidu.com")
})

YAML方式

r.GET("/user/save", func(ctx *gin.Context) {ctx.YAML(200, gin.H{"name": "ms", "age": 19})
})

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

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

相关文章

哈尔滨算力服务器托管推荐-青蛙云

哈尔滨年平均气温3.5摄氏度,有发展云计算和算力数据中心的天然优势 ,今天为哈尔滨算力服务器托管服务商:青蛙云,黑龙江经营17年的老牌IDC服务商。 先来了解下算力服务器: 算力服务器,尤其是那些用于运行人…

【C++】每日一练(有效的括号)

本篇博客给大家带来的是用C语言来解答有效的括号! 🐟🐟文章专栏:每日一练 🚀🚀若有问题评论区下讨论,我会及时回答 ❤❤欢迎大家点赞、收藏、分享! 今日思想:不服输的少年…

Embedding模型到底是什么?

嵌入模型(Embedding Model)是一种将高维数据映射到低维空间的工具,广泛应用于自然语言处理(NLP)、推荐系统和图像识别等领域。它的核心目标是将复杂的数据(如文本、图像或用户行为)转换为稠密的…

Centos离线安装perl

文章目录 Centos离线安装perl1. perl是什么?2. Centos下载地址?3. perl的安装4. 安装结果验证 Centos离线安装perl 1. perl是什么? Perl 是一种 高级脚本语言,诞生于 1987 年,以强大的 文本处理能力 和灵活性著称&…

快速学习Bootstrap前端框架

什么是 Bootstrap? Bootstrap 是一个开源的前端框架,用于快速开发响应式(Responsive)和美观的网页。它包含: ✅ HTML 组件(导航栏、按钮、表单等) ✅ CSS 样式(网格系统、排版、颜色等) ✅ JavaScript 交互(模态框、轮播图、工具提示等) 官网:Bootstrap The mo…

51单片机的keil c51软件安装教程

Keil(C51)介绍、下载、安装与注册_keil c51-CSDN博客 参考 安装 不一定是这个大小,也可以下载别的版本KEID C51 注册 加入芯片型号 …

DeepIn Wps 字体缺失问题

系统缺失字体 Symbol 、Wingdings 、Wingdings2、Wingdings3、MT—extra 字体问题 问了下DeepSeek 在应用商店安装或者在windows 里面找 装了一个GB-18030 还是不行 在windows里面复制了缺失的字体 将字体复制到DeepIn 的字体目录(Ubuntu 应该也是这个目录&am…

chebykan阅读收尾

sciml SciML 是 科学机器学习 (Scientific Machine Learning) 的缩写,它指的是将机器学习方法应用于解决科学问题,例如物理、化学、生物学等领域中的问题。SciML 旨在利用机器学习的强大能力来提高科学计算的效率和准确性。 SciML 的主要问题: 数据获取…

SpringBoot使用Logback日志框架与综合实例

日志框架的使用,系列文章: 《SpringBoot使用Logback日志框架与综合实例》 《SpringBoot使用@Slf4j注解实现日志输出》 《Log4j2日志记录框架的使用教程与简单实例》 《SpringBoot使用AspectJ实现AOP记录接口:请求日志、响应日志、异常日志》 《SpringBoot使用AspectJ的@Arou…

【性能测试】Jmeter详细操作-小白使用手册(2)

本篇文章主要介绍Jmeter中如何使用 JSON断言、同步定时器、事务控制器、CSV数据文件设置、HTTP Cookie管理器 目录 一:JSON断言 1:正确结果展示 2:错误结果展示 3:JSON配置 (1)Additionally assert …

分布式锁—Redisson的同步器组件

1.Redisson的分布式锁简单总结 Redisson分布式锁包括:可重入锁、公平锁、联锁、红锁、读写锁。 (1)可重入锁RedissonLock 非公平锁,最基础的分布式锁,最常用的锁。 (2)公平锁RedissonFairLock 各个客户端尝试获取锁时会排队,按照队…

国产编辑器EverEdit - 脚本(解锁文本编辑的无限可能)

1 脚本 1.1 应用场景 脚本是一种功能扩展代码,用于提供一些编辑器通用功能提供不了的功能,帮助用户在特定工作场景下提高工作效率,几乎所有主流的编辑器、IDE都支持脚本。   EverEdit的脚本支持js(语法与javascript类似)、VBScript两种编程…

服务器上的nginx因漏洞扫描需要升级

前言 最近客户联系说nginx存在安全漏洞 F5 Nginx 安全漏洞(CVE-2024-7347) F5Nginx是美国F5公司的一款轻量级Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like协议下发行。F5 Nginx存在安全漏洞,该漏洞源于可能允许攻击者使用特制的…

ASP.NET CORE MVC EF框架

1.一个视图中的多个表单Form中的变量。 方式一:视图中跨Form变量不能用,得各自定义变量否则编译不能通过。变量名还不能相同。 或者方式二:在Form之外定义变量 {ViewData["Title"] "ExpenseForm"; }  {L…

【MySQL 中 `TINYINT` 类型与布尔值的关系】

MySQL 中 TINYINT 类型与布尔值的关系 在 MySQL 数据库中,BOOLEAN 类型并不存在,BOOLEAN 或 BOOL 都是 TINYINT(1) 的别名。通常,TINYINT(1) 类型用于存储布尔值。 1. TINYINT 类型介绍 TINYINT 是一个占用 1 字节的整数类型,取…

【Rust基础】Rust后端开发常用库

使用Rust有一段时间了,期间尝试过使用Rust做后端开发、命令行工具开发,以及做端侧模型部署,也尝试过交叉编译、FFI调用等,也算是基本入门了。在用Rust做后端接口开发时,常常会找不到一些合适库,而这些库在J…

[leetcode]位运算

一.AND &运算 注:两个操作数做&运算结果是不会变大的 二.OR |运算 注:两个操作数做|运算结果是不会变小的 三.XOR(异或) ^运算 注:结果可能变大也可能变小也可能不变,但是不会导致进位,比如两个四位的数字做…

常见FUZZ姿势与工具实战:从未知目录到备份文件漏洞挖掘

本文仅供学习交流使用,严禁用于非法用途。未经授权,禁止对任何网站或系统进行未授权的测试或攻击。因使用本文所述技术造成的任何后果,由使用者自行承担。请严格遵守《网络安全法》及相关法律法规! 目录 本文仅供学习交流使用&am…

前置机跟服务器的关系

在复杂的IT系统架构中,前置机与服务器的协同配合是保障业务高效、安全运行的关键。两者的关系既非简单的上下级,也非独立个体,而是通过功能分层与职责分工,构建起一套既能应对高并发压力、又能抵御安全风险的弹性体系。 在当今复…

MySQL中有哪些索引

1,B-Tree索引:常见的索引类型 2,哈希索引:基于哈希表实现,只支持等值查询 ,只有Memory存储引擎和NDB Cluster存储引擎显示支持哈希索引 3,全文索引:可在字符列上创建(T…