【Gin】Gin框架介绍和使用
一、简单使用Gin框架搭建一个服务器
package mainimport ("github.com/gin-gonic/gin"
)func main() {// 创建一个默认的路由引擎r := gin.Default()// GET 请求方法r.GET("/hello", func(c *gin.Context) {// c.JSON 返回的是JSON格式的数据c.JSON(200, gin.H{"message" : "hello world",})}// 启动HTTP服务器,默认在 0.0.0.0:8080 启动r.Run()
}
这里,我们只需要记住一下几个函数就可以快速启动一个服务器:还有记住就是一个请求对应一个响应。世界是一个巨大的IO。
gin.Default() // 创建一个默认的路由引擎GET("/路由", func(c *gin.Context) {}c.JSON(状态码, gin.H{})r.Run() // 启动HTTP服务器
二、RESTful API
REST 与技术无关,代表的是一种软件架构风格,简单地说,REST的含义就是客户端与服务器之间进行交互的时候,使用HTTP协议中的4种请求方法代表不同的动作。
- GET用来获取资源
- POST用来新建资源
- PUT用来更新资源
- DELETE用来删除资源
只要API程序遵循了REST风格,那就可以称其为RESTful API。目前在前后端分离的架构中,前后端基本都是通过RESTful API来进行交互的。
我们可以来看一看下面的代码:
func main() {r := gin.Default()r.GET("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "GET",})})r.POST("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "POST",})})r.PUT("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "PUT",})})r.DELETE("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "DELETE",})})
}
三、Gin获取参数
前三个进行获取参数的函数都有三种方法,且函数的格式基本一样:
3.1 获取 querystring 参数
querystring 指的是 URL中 ? 后面携带的参数:/user/search?username=小王子&address=沙河,获取请求的 querystring 参数的方法如下:
func main() {//Default返回一个默认的路由引擎r := gin.Default()r.GET("/user/search", func(c *gin.Context) {username := c.DefaultQuery("username", "小王子")//username := c.Query("username")address := c.Query("address")//输出json结果给调用方c.JSON(http.StatusOK, gin.H{"message": "ok","username": username,"address": address,})})r.Run()
}c.Query()c.DefaultQuery()
我之前写的一个项目就是需要处理这种URL,不过是在C++上处理,需要将URL获取到,然后进行字符串的切割。
3.2 获取 form 参数
当前端请求的数据是通过form表单提交的时候,例如向 /user/search 发一个POST请求,获取请求数据的方式如下:
func main() {//Default返回一个默认的路由引擎r := gin.Default()r.POST("/user/search", func(c *gin.Context) {// DefaultPostForm取不到值时会返回指定的默认值//username := c.DefaultPostForm("username", "小王子")username := c.PostForm("username")address := c.PostForm("address")//输出json结果给调用方c.JSON(http.StatusOK, gin.H{"message": "ok","username": username,"address": address,})})r.Run(":8080")
}c.PostForm()c.DefaultPostForm()
3.3 获取 JSON 参数
当前端请求的数据通过JSON提交的时候,例如向 /json 发送一个JSON格式的POST请求,则请求参数的方式如下:
r.POST("/json", func(c *gin.Context) {// 注意:下面为了举例子方便,暂时忽略了错误处理b, _ := c.GetRawData() // 从c.Request.Body读取请求数据// 定义map或结构体var m map[string]interface{}// 反序列化_ = json.Unmarshal(b, &m)c.JSON(http.StatusOK, m)
})
3.4 获取 path 参数
请求的参数通过URL路径传递,例如:/user/search/小王子/沙河。获取请求URL路径中的参数的方式如下:
func main() {//Default返回一个默认的路由引擎r := gin.Default()r.GET("/user/search/:username/:address", func(c *gin.Context) {username := c.Param("username")address := c.Param("address")//输出json结果给调用方c.JSON(http.StatusOK, gin.H{"message": "ok","username": username,"address": address,})})r.Run(":8080")
}c.Param()c.DefaultParam()
3.5 参数绑定
为了可以更方便的获取请求相关参数,提高开发效率,我们可以基于请求的 Content-Type 识别请求数据类型并利用反射机制自动提取请求中 QueryString、form 表单、JSON、XML等参数到结构体中,我们可以使用 .ShouldBind() 函数来进行强大的功能,他能够基于请求自动提取 JSON、form表单和QueryString 类型的数据,并把值绑定到指定的结构体对象。
// Binding from JSON
type Login struct {User string `form:"user" json:"user" binding:"required"`Password string `form:"password" json:"password" binding:"required"`
}func main() {router := gin.Default()// 绑定JSON的示例 ({"user": "q1mi", "password": "123456"})router.POST("/loginJSON", func(c *gin.Context) {var login Loginif err := c.ShouldBind(&login); err == nil {fmt.Printf("login info:%#v\n", login)c.JSON(http.StatusOK, gin.H{"user": login.User,"password": login.Password,})} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})// 绑定form表单示例 (user=q1mi&password=123456)router.POST("/loginForm", func(c *gin.Context) {var login Login// ShouldBind()会根据请求的Content-Type自行选择绑定器if err := c.ShouldBind(&login); err == nil {c.JSON(http.StatusOK, gin.H{"user": login.User,"password": login.Password,})} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})// 绑定QueryString示例 (/loginQuery?user=q1mi&password=123456)router.GET("/loginForm", func(c *gin.Context) {var login Login// ShouldBind()会根据请求的Content-Type自行选择绑定器if err := c.ShouldBind(&login); err == nil {c.JSON(http.StatusOK, gin.H{"user": login.User,"password": login.Password,})} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})// Listen and serve on 0.0.0.0:8080router.Run(":8080")
}
ShouldBind 会按照下面的顺序解析请求中的数据进行绑定:
- 如果是
GET
请求,只使用Form
绑定引擎(query
)。 - 如果是
POST
请求,首先检查content-type
是否为JSON
或XML
,然后再使用Form(form-data)
四、文件上传
4.1 单个文件上传
文件上传前端页面代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head><title>上传文件示例</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data"><input type="file" name="f1"><input type="submit" value="上传">
</form>
</body>
</html>
后端 gin 框架部分代码:
func main() {router := gin.Default()// 处理multipart forms提交文件时默认的内存限制是32 MiB// 可以通过下面的方式修改// router.MaxMultipartMemory = 8 << 20 // 8 MiBrouter.POST("/upload", func(c *gin.Context) {// 单个文件file, err := c.FormFile("f1")if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}log.Println(file.Filename)dst := fmt.Sprintf("C:/tmp/%s", file.Filename)// 上传文件到指定的目录c.SaveUploadedFile(file, dst)c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("'%s' uploaded!", file.Filename),})})router.Run()
}
4.2 多个文件上传
五、重定向
5.1 HTTP重定向
r.GET("/test", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
})
5.2 路由重定向
r.GET("/test", func(c *gin.Context) {// 指定重定向的URLc.Request.URL.Path = "/test2"r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"hello": "world"})
})
六、Gin路由
6.1 普通路由
6.2 路由组
七、Gin中间件
我感觉这个中间件有点像C++回调函数。Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
7.1 定义中间件
Gin中的中间件必须是一个 gin.HandlerFunc 类型的。
// StatCost 是一个统计耗时请求耗时的中间件
func StatCost() gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值// 调用该请求的剩余处理程序c.Next()// 不调用该请求的剩余处理程序// c.Abort()// 计算耗时cost := time.Since(start)log.Println(cost)}
}
7.2 注册中间件
func main() {// 新建一个没有任何默认中间件的路由r := gin.New()// 注册一个全局中间件r.Use(StatCost())r.GET("/test", func(c *gin.Context) {name := c.MustGet("name").(string) // 从上下文取值log.Println(name)c.JSON(http.StatusOK, gin.H{"message": "Hello world!",})})r.Run()
}
// 给/test2路由单独注册中间件(可注册多个)r.GET("/test2", StatCost(), func(c *gin.Context) {name := c.MustGet("name").(string) // 从上下文取值log.Println(name)c.JSON(http.StatusOK, gin.H{"message": "Hello world!",})})
shopGroup := r.Group("/shop", StatCost())
{shopGroup.GET("/index", func(c *gin.Context) {...})...
}shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{shopGroup.GET("/index", func(c *gin.Context) {...})...
}
7.3 中间件注意事项
7.3.1 gin 默认中间件
gin.Default()
默认使用了Logger
和Recovery
中间件,其中:
Logger
中间件将日志写入gin.DefaultWriter
,即使配置了GIN_MODE=release
。Recovery
中间件会recover任何panic
。如果有panic的话,会写入500响应码。
如果不想使用上面两个默认的中间件,可以使用gin.New()
新建一个没有任何默认中间件的路由
7.3.2 gin 中间件中使用 goroutine
当在中间件或handler
中启动新的goroutine
时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy()
)。
相关文章:
【Gin】Gin框架介绍和使用
一、简单使用Gin框架搭建一个服务器 package mainimport ("github.com/gin-gonic/gin" )func main() {// 创建一个默认的路由引擎r : gin.Default()// GET 请求方法r.GET("/hello", func(c *gin.Context) {// c.JSON 返回的是JSON格式的数据c.JSON(200, g…...
AI大模型带来哪些创业机遇?
AI 大模型的快速发展带来了许多创新和创业机遇,涵盖了从行业应用到基础设施优化的方方面面。以下是一些具体的创业机会: 1、垂直行业应用 大模型可以根据不同行业的需求进行定制和优化,提供高度专业化的 AI 解决方案。 医疗领域:…...

[Linux] 层层深入理解文件系统——(3)磁盘组织存储的文件
标题:[Linux] 层层深入理解文件系统——(3)磁盘组织组织存储的文件 个人主页水墨不写bug 目录 一、磁盘中的文件 1)磁盘的物理结构 2)磁盘的CHS寻址法 3)磁盘的空间管理 二、磁盘如何组织存储文件 三…...
Apache Cordova学习计划
Apache Cordova(之前称为 PhoneGap): 1. PhoneGap的起源:2008年8月,PhoneGap在旧金山的iPhoneDevCamp上首次亮相,由Nitobe公司开发,目的是“为跨越Web技术和iPhone之间的鸿沟牵线搭桥”。 2. Ph…...
Unity学习日志-API
Untiy基本API 角度旋转自转相对于某一个轴 转多少度相对于某一个点转练习 角度 this.transform.rotation(四元数)界面上的xyz(相对于世界坐标) this.transform.eulerAngles;相对于父对象 this.transform.localEulerAngles;设置角度和设置位置一样,不能单独设置xz…...

Java基础常见面试题总结(上)
基础概念与常识 Java 语言有哪些特点? 简单易学(语法简单,上手容易);面向对象(封装,继承,多态);平台无关性( Java 虚拟机实现平台无关性)&…...

4 -《本地部署开源大模型》在Ubuntu 22.04系统下部署运行ChatGLM3-6B模型
在Ubuntu 22.04系统下部署运行ChatGLM3-6B模型 大模型部署整体来看并不复杂,且官方一般都会提供标准的模型部署流程,但很多人在部署过程中会遇到各种各样的问题,很难成功部署,主要是因为这个过程会涉及非常多依赖库的安装和更新及…...

本地如何使用Pycharm连接远程服务器调试torchrun
pycharm 远程连接服务器并且debug, 支持torch.distributed.launch debug_pycharm远程debug-CSDN博客 上面这个博客写的真的非常好,记录一下,需要注意该博主的主机为mac 本人可调试版本为: 可直接运行版本为:...
Visual Studio 2022常用快捷键
1. 基本编辑快捷键 Ctrl X:剪切选中内容Ctrl C:复制选中内容Ctrl V:粘贴内容Ctrl Z:撤销Ctrl Y:重做Ctrl Shift L:删除当前行Ctrl K, Ctrl C:注释选中的代码Ctrl K, Ctrl U…...

mysql innodb 引擎如何直接复制数据库文件?
mysql innodb 引擎如何直接复制数据库文件?介绍如下: 1、首先找到数据库文件所在位置 一般可以看my.conf/my.ini配置的文件的“datadir” 看示例: “MAMP”在Macos下的数据库文件位置: /Library/Application Support/appsolu…...
python中的global和nonlocal关键字以及闭包和模块
global i 这样的用法在于 Python 中,但需要在一个函数内部使用,以便将变量 i 声明为全局变量。让我们来详细讲解一下它的用法。 什么是全局变量? 全局变量是指在函数外部定义的变量,可以在任何函数中访问和修改。如果你需要在函数…...

LabVIEW风机滚动轴承监测系统
矿井主通风机作为矿井中最重要的通风设备,一旦出现故障,不仅会影响矿井内的空气质量,还可能引发安全事故。研究表明,通风机中约30%的故障是由轴承问题引起的。因此,能够实时监控矿井主通风机轴承状态的系统,…...
第1节 什么是鸿蒙系统
鸿蒙系统(HarmonyOS)是华为公司发布的一款基于微内核的面向全场景的分布式操作系统。以下是对它的具体介绍: 1. 核心特点: • 分布式能力:这是鸿蒙系统的核心优势之一。它能够将多种不同类型的智能终端设备连接起来&a…...
CentOS 7 将 YUM 源更改为国内镜像源
在 CentOS 7 中,将 YUM 源更改为国内的阿里云镜像源可以提高软件包的下载速度。以下是具体的步骤: 1. 备份原有 YUM 源配置 首先,建议你备份当前的 YUM 源配置,以防后续需要恢复: sudo cp -r /etc/yum.repos.d /etc…...

python调用dircmp进行文件夹比较
不同电脑上的同一部署文件,由于更新频率不相同导致两边内容有差异,需要比较两边的文件夹及文件差异。之前写过批量修改文件名的Python代码,因此优先想用python处理。 百度“python 文件夹对比”,不少文章都是自己实现的文件夹…...
微信小程序 - 供应链系统设计
文章目录 一、系统概述二、系统架构设计三、系统安全设计四、系统性能优化五、系统部署与维护 在当今数字化时代,供应链管理对于企业的高效运营至关重要。微信小程序作为一种便捷的移动应用形式,为供应链系统的开发提供了新的机遇。本文将从系统架构设计…...

嵌入式学习-IO进程-Day03
嵌入式学习-IO进程-Day03 IO进程 获取文件属性(stat) 库 库的概念 库的分类 静态库的制作 动态库的制作 进程 进程和程序的区别 进程的特点 进程三段 进程的类型 进程的运行状态 进程状态转换图(重点) 进程的函数接口 创建进程for…...

docker安装elasticsearch和ik分词器
目录 ElasticSearch 了解ElasticSearch ELK技术栈 编辑 ElasticSearch与lucene的关系 总结 倒排索引 正向索引 倒排索引 正向和倒排 elasticSearch特定的一些概念 文档和字段 索引和映射 mysql与elasticsearch对比 安装elasticSeacher并部署单例es 创建网络 加…...

|智能门票|008_django基于Python的智能门票设计与实现2024_i16z2v70
目录 系统展示 设计步骤 代码实现 项目案例 获取源码 博主介绍:CodeMentor毕业设计领航者、全网关注者30W群落,InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者,博客领航之星、开发者头条/腾讯云/AW…...

QFramework v1.0 使用指南 更新篇:20240919. 新增 BindableDictionary
增加了三个比较常用的屏幕过渡:FadeIn,FadeOut,FadeInOut。 示例代码如下: using UnityEngine;namespace QFramework.Example {public class ScreenTransitionsExample : MonoBehaviour{private void OnGUI(){IMGUIHelper.SetDesignResolut…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...