go go go 出发咯 - go web开发入门系列(二) Gin 框架实战指南


往期回顾

  • go go go 出发咯 - go web开发入门系列(一) helloworld

前言

前一节我们使用了go语言简单的通过net/http搭建了go web服务,但是仅使用 Go 的标准库 net/http 来构建复杂的 Web 应用可能会有些繁琐。这时,一个优秀的 Web 框架就显得至关重要。Gin 就是其中最受欢迎的选择之一。它是一个用 Go 编写的高性能 Web 框架,以其极快的速度和丰富的功能集而闻名。

在本篇博客中,我们将带你从零开始,一步步学习如何使用 Gin 框架搭建你的第一个 Web 应用。


为什么选择 Gin?

在众多 Go Web 框架中,Gin 脱颖而出,主要有以下几个原因:

  • 极致性能:Gin 的路由基于 Radix 树,内存占用极小,性能表现卓越,是 Go 社区中最快的框架之一。
  • 中间件支持:Gin 的中间件(Middleware)机制非常强大,可以将一系列可插拔的组件(如日志、授权、Gzip 压缩)串联起来,作用于请求处理的生命周期中。
  • 错误管理:Gin 提供了一种便捷的方式来收集和处理 HTTP 请求期间发生的所有错误,让你的应用更加健壮。
  • JSON 验证:Gin 可以轻松地解析和验证请求中的 JSON 数据,这对于构建 RESTful API 至关重要。
  • 路由组:通过路由组(Route Grouping),你可以更好地组织你的路由,例如将需要相同授权中间件的路由归为一组。
  • 上手简单:Gin 的 API 设计非常直观,学习曲线平缓,文档齐全,对新手非常友好。

准备工作

在开始之前,请确保你已经完成了以下准备:

  1. 安装 Go 环境:访问 Go 官方网站 下载并安装适合你操作系统的 Go 版本(建议 1.18 或更高版本,我使用的是1.24.4)。
  2. 配置你的工作区:设置好你的 GOPATHGOROOT 环境变量。
  3. 一个代码编辑器:推荐使用 VS Code 并安装 Go 扩展,或者使用 GoLand。

第一个 Gin 应用:“Hello, Gin!”

第一步:创建项目

首先,创建一个新的项目目录,并使用 Go Modules 初始化项目。

如果是使用vscode的童鞋,参见以下代码:

# 创建一个项目文件夹
mkdir gin-hello-world
cd gin-hello-world# 初始化 Go 模块
go mod init gin-hello-world
`go mod init` 命令会创建一个 `go.mod` 文件,用于跟踪和管理项目的依赖。

第二步:下载Gin 依赖

在当前项目目录下,键入如下命令,安装Gin依赖

 go get -u github.com/gin-gonic/gin

如果你使用的是 Goland 存在拉取 Gin依赖失败的情况,请配置GoProxy

GOPROXY=https://goproxy.cn,direct.

请添加图片描述

第二步:编写main.go

main.go

package mainimport "github.com/gin-gonic/gin"func main() {// 1. 创建一个默认的 Gin 引擎r := gin.Default()// 2. 定义一个路由和处理函数// 当客户端以 GET 方法请求 /hello 路径时,执行后面的匿名函数r.GET("/hello", func(c *gin.Context) {// c.JSON 是一个辅助函数,可以序列化给定的结构体为 JSON 并写入响应体c.JSON(200, gin.H{"message": "Hello, Gin!",})})// 3. 启动 HTTP 服务器r.Run(":8888")
}

直接运行main.go,访问localhost:8888/hello或者使用请求工具

curl http://localhost:8888/hello

请添加图片描述

可以收到一个json的返回

{"message":"Hello, Gin!"}

Gin 核心概念深入

掌握了基础之后,让我们来探索 Gin 的一些核心功能。

1. 路由(Routing)

Gin 提供了非常灵活的路由功能。

路由参数

你可以定义包含动态参数的路由。

r.GET("/users/:name", func(c *gin.Context) {// 使用 c.Param() 获取路由参数name := c.Param("name")c.String(200, "Hello, %s", name)
})

测试:访问 http://localhost:8888/users/jerry,你会看到 Hello, jerry

请添加图片描述

查询字符串参数

获取 URL 中的查询参数(如 ?page=1&size=10)。

r.GET("/articles", func(c *gin.Context) {// 使用 c.DefaultQuery() 获取参数,如果不存在则使用默认值page := c.DefaultQuery("page", "1")// 使用 c.Query() 获取参数size := c.Query("size") // 如果不存在,返回空字符串c.JSON(200, gin.H{"page": page,"size": size,})
})

测试:访问 http://localhost:8888/articles?page=2&size=20

请添加图片描述

处理 POST 请求和数据绑定

构建 API 不可避免地要处理 POST 请求,通常是 JSON 格式的数据。Gin 的数据绑定功能可以极大地简化这个过程。

首先,定义一个与 JSON 结构匹配的 Go 结构体:

// 定义一个 Article 结构体
type Article struct {Title   string `json:"title" binding:"required"`Content string `json:"content" binding:"required"`
}

binding:"required" 标签表示这个字段是必需的。

然后,创建一个处理 POST 请求的路由:

r.POST("/articles", func(c *gin.Context) {// 声明一个 Article 类型的变量var article Article// 使用 ShouldBindJSON 将请求的 JSON body 绑定到 article 变量上// ShouldBindJSON 会在绑定失败时返回错误,但不会中止请求if err := c.ShouldBindJSON(&article); err != nil {// 如果绑定失败,返回一个 400 错误和错误信息c.JSON(400, gin.H{"error": err.Error()})return}// 绑定成功,返回一个 200 成功响应和接收到的数据c.JSON(200, gin.H{"status":  "received","title":   article.Title,"content": article.Content,})
})

使用 curl 或者 postman 来测试这个 POST 端点:

curl -X POST http://localhost:8888/articles \-H "Content-Type: application/json" \-d '{"title":"aaaa", "content":"123456789"}'

请添加图片描述

你会收到成功的响应。如果尝试发送不完整的数据(例如缺少 title),你会收到一个 400 错误。

请添加图片描述

2. 路由组 (Router Grouping)

当应用变大时,路由会变得复杂。路由组可以帮助你更好地组织代码,并为一组路由共享中间件。

类似于 SpringBoot 中 @RequestMapping("/api/v1") 设置公共请求路径。

func main() {r := gin.Default()// 创建一个 /api/v1 的路由组v1 := r.Group("/api/v1"){// 在 v1 组下定义路由v1.GET("/users", func(c *gin.Context) {c.JSON(200, gin.H{"users": []string{"Alice", "Bob", "Charlie"}})})v1.GET("/products", func(c *gin.Context) {c.JSON(200, gin.H{"products": []string{"Laptop", "Mouse"}})})}// 创建一个 /api/v2 的路由组v2 := r.Group("/api/v2"){v2.GET("/users", func(c *gin.Context) {c.JSON(200, gin.H{"message": "v2 users endpoint"})})}r.Run()
}

现在,你可以通过 /api/v1/users/api/v2/users 访问不同版本的 API。

3. 中间件 (Middleware)

中间件是 Gin 的精髓所在。它是一个在请求被处理之前或之后执行的函数。gin.Default() 就默认使用了 Logger 和 Recovery 中间件。

类似于SpringBoot aop切面实现的全局请求拦截器。只不过再go中被叫做中间件。

让我们来创建一个自定义的日志中间件。

package mainimport ("log""time""github.com/gin-gonic/gin"
)// 自定义日志中间件
func LoggerMiddleware() gin.HandlerFunc {return func(c *gin.Context) {// 请求开始时间startTime := time.Now()// 调用 c.Next() 执行后续的处理函数c.Next()// 请求结束时间endTime := time.Now()// 计算执行时间latencyTime := endTime.Sub(startTime)// 获取请求方法和路径reqMethod := c.Request.MethodreqUri := c.Request.RequestURI// 获取状态码statusCode := c.Writer.Status()// 获取客户端 IPclientIP := c.ClientIP()// 打印日志log.Printf("| %3d | %13v | %15s | %s | %s |",statusCode,latencyTime,clientIP,reqMethod,reqUri,)}
}func main() {r := gin.New() // 使用 gin.New() 创建一个没有任何中间件的引擎// 全局使用我们的自定义日志中间件r.Use(LoggerMiddleware())// 使用 Gin 默认的 Recovery 中间件,防止 panic 导致程序崩溃r.Use(gin.Recovery())r.GET("/test-middleware", func(c *gin.Context) {c.JSON(200, gin.H{"message": "Middleware test successful!"})})r.Run()
}

这个中间件会记录每个请求的状态码、耗时、IP、方法和路径。你可以用它来替换 Gin 默认的 Logger,或者为特定路由组添加认证中间件。

关于使用r := gin.New() 的代码解释,

通过使用 gin.New() 创建一个没有任何中间件的引擎,相比 gin.default()创建的更纯净,因为gin.default()自带了两个中间件:

  • gin.Logger(): Gin 自带的日志中间件,会在控制台打印每条请求的日志。
  • gin.Recovery(): 一个恢复(Recovery)中间件,它能捕获任何 panic,防止整个程序因此崩溃,并会返回一个 500 错误。
  • 即 gin.default() 等价于 r := gin.New();r.Use(gin.Logger(), gin.Recovery())

所以为了体验更纯粹的gin并设置自定义的日志中间件,使用了gin.new(),当然也可以使用gin.default,只不过日志信息会有重叠

请添加图片描述

4. HTML 模板渲染

虽然 Gin 常用于构建 API,但它同样能出色地渲染 HTML 页面。

第一步:创建模板文件

在你的项目根目录下创建一个 templates 文件夹,并在其中创建一个 index.html 文件。

templates/index.html:

类似于java 中的Springboot thymeleaf 模板的方式,在模板之间进行传递参数进行渲染

<!DOCTYPE html>
<html>
<head><title>{{ .title }}</title>
</head>
<body><h1>Hello, {{ .name }}!</h1><p>Welcome to our website rendered by Gin.</p>
</body>
</html>

第二步:编写 Go 代码

修改 main.go 来加载并渲染这个模板。

package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 告诉 Gin 模板文件在哪里r.LoadHTMLGlob("templates/*")r.GET("/index", func(c *gin.Context) {// 使用 c.HTML 渲染模板// 我们传递一个 gin.H 对象,模板中可以通过 .key 的方式访问数据c.HTML(http.StatusOK, "index.html", gin.H{"title": "Gin Template Rendering","name":  "Guest",})})r.Run()
}

运行程序并访问 http://localhost:8888/index,你将看到一个动态渲染的 HTML 页面。

请添加图片描述

5. 文件上传

处理文件上传是 Web 应用的常见需求。Gin 让这个过程变得异常简单。

第一步:更新 HTML 模板

templates 目录下创建一个 upload.html

templates/upload.html:

<!DOCTYPE html>
<html>
<head><title>File Upload</title>
</head>
<body><h2>Upload a File</h2><form action="/upload" method="post" enctype="multipart/form-data"><input type="file" name="file"><input type="submit" value="Upload"></form>
</body>
</html>

第二步:编写后端处理逻辑

package mainimport ("fmt""net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.LoadHTMLGlob("templates/*")// 为上传文件设置一个较低的内存限制 (默认是 32 MiB)r.MaxMultipartMemory = 8 << 20  // 8 MiB// 提供上传页面的路由r.GET("/upload", func(c *gin.Context) {c.HTML(http.StatusOK, "upload.html", nil)})// 处理文件上传的路由r.POST("/upload", func(c *gin.Context) {// 从表单中获取文件file, err := c.FormFile("file")if err != nil {c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))return}// 将上传的文件保存到服务器上的指定位置// 这里我们保存在项目根目录下的 "uploads/" 文件夹中// 请确保你已经手动创建了 "uploads" 文件夹dst := "./uploads/" + file.Filenameif err := c.SaveUploadedFile(file, dst); err != nil {c.String(http.StatusInternalServerError, fmt.Sprintf("upload file err: %s", err.Error()))return}c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded successfully!", file.Filename))})r.Run()
}

在运行前,请务必在项目根目录手动创建一个名为 uploads 的文件夹。然后运行程序,访问 http://localhost:8888/upload,你就可以选择并上传文件了。

请添加图片描述

6. 重定向 (Redirection)

HTTP 重定向也是一个常用功能。Gin 使用 c.Redirect() 方法来处理。

这个方法接受两个参数:

  1. HTTP 状态码:常用的有 http.StatusMovedPermanently (301, 永久重定向) 和 http.StatusFound (302, 临时重定向)。
  2. 目标 URL:你想要重定向到的地址,可以是相对路径或绝对路径。
package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 示例1: 临时重定向// 访问 /test-redirect 会被重定向到外部网站r.GET("/test-redirect", func(c *gin.Context) {c.Redirect(http.StatusFound, "https://www.google.com")})// 示例2: 永久重定向内部路由// 访问 /old-path 会被永久重定向到 /new-pathr.GET("/old-path", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "/new-path")})r.GET("/new-path", func(c *gin.Context) {c.JSON(200, gin.H{"message": "Welcome to the new path!"})})r.Run()
}

当你访问 http://localhost:8888/test-redirect 时,你的浏览器地址栏会变成 https://www.google.com。当你访问 http://localhost:8888/old-path 时,浏览器会跳转到 http://localhost:8888/new-path 并显示 JSON 消息。


总结

通过这篇终极指南,我们系统地学习了如何使用 Gin 框架构建一个功能完善的 Web 应用。我们从基础的 “Hello, World” 出发,深入探索了路由、数据绑定、路由组、自定义中间件、HTML 模板渲染、文件上传和重定向等一系列核心功能。

这已经为你打下了坚实的基础。接下来,你可以继续探索更高级的主题,例如:

  • 与数据库集成:将你的 Gin 应用连接到 MySQL、PostgreSQL 或 GORM。
  • WebSocket 支持:构建实时通信应用。
  • 部署:将你的 Gin 应用打包成 Docker 镜像并部署到服务器。

希望这篇博客能为你打开 Go Web 开发的大门。Gin 是一个强大而有趣的工具,现在就开始用它来构建你的下一个项目吧!

有用的链接:

  • Gin 官方文档
  • Go 官方网站

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

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

相关文章

编译OpenHarmony-4.0-Release RK3566 报错

编译OpenHarmony-4.0-Release RK3566 报错1. 报错问题2.问题解决3.解决方案4.​调试技巧​subsystem name config incorrect in ‘/home/openharmony/OpenHarmony/vendor/kaihong/khdvk_356b/bundle.json’, build file subsystem name is kaihong_products,configured subsy1.…

【PTA数据结构 | C语言版】线性表循环右移

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 给定顺序表 A(a1​,a2​,⋯,an​)&#xff0c;请设计一个时间和空间上尽可能高效的算法将该线性表循环右移指定的 m 位。例如&#xff0c;(1,2,5,7,3,4,6,8) 循环右移 3 位&#xff08;m3) 后的结果…

c++-内部类

概念如果一个类定义在另一个类的内部&#xff0c;这个内部类就叫做内部类。内部类是一个独立的类&#xff0c; 它不属于外部类。特性1.不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。 2.内部类就是外部类的友元类&#xff0c;参见友元类的定…

.golangci.yml文件配置

version: “2” run: timeout: 5m concurrency: 10 modules-download-mode: readonly linters: default: standard enable: - revive - cyclop settings: staticcheck: initialisms: [ “ACL”, “API”, “ASCII”, “CPU”, “CSS”, “DNS”, “EOF”, “GUID”, “HTML”, …

YOLO模型魔改指南:从原理到实战,替换Backbone、Neck和Head(战损版)

前言 Hello&#xff0c;大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列是作者参加DataWhale 2025年6月份Yolo原理组队学习的技术笔记文档&#xff0c;这里整理为博客&#xff0c;希望能帮助Yolo的开发者少走弯路&#xff01; &am…

Swift 图论实战:DFS 算法解锁 LeetCode 323 连通分量个数

文章目录摘要描述示例题解答案DFS 遍历每个连通区域Union-Find&#xff08;并查集&#xff09;题解代码分析&#xff08;Swift 实现&#xff1a;DFS&#xff09;题解代码详解构建邻接表DFS 深度优先搜索遍历所有节点示例测试及结果示例 1示例 2示例 3时间复杂度分析空间复杂度分…

【剑指offer】栈 队列

&#x1f4c1; JZ9 用两个栈实现队列一个栈in用作进元素&#xff0c;一个栈out用于出元素。当栈out没有元素时&#xff0c;从in栈获取数据&#xff0c;根据栈的特性&#xff0c;栈out的top元素一定是先进入的元素&#xff0c;因此当栈out使用pop操作时&#xff0c;一定时满足队…

GoView 低代码数据可视化

纯前端 分支&#xff1a; master &#x1f47b; 携带 后端 请求分支: master-fetch &#x1f4da; GoView 文档 地址&#xff1a;https://www.mtruning.club/ 项目纯前端-Demo 地址&#xff1a;https://vue.mtruning.club/ 项目带后端-Demo 地址&#xff1a;https://demo.mtrun…

Spring Boot返回前端Long型丢失精度 后两位 变成00

文章目录一、前言二、问题描述2.1、问题背景2.2、问题示例三、解决方法3.1、将ID转换为字符串3.2、使用JsonSerialize注解3.3、使用JsonFormat注解一、前言 在后端开发中&#xff0c;我们经常会遇到需要将ID作为标识符传递给前端的情况。当ID为long类型时&#xff0c;如果该ID…

计算机网络实验——无线局域网安全实验

实验1. WEP和WPA2-PSK实验一、实验目的验证AP和终端与实现WEP安全机制相关的参数的配置过程。验证AP和终端与实现WPA2-PSK安全机制相关的参数的配置过程。验证终端与AP之间建立关联的过程。验证关闭端口的重新开启过程。验证属于不同BSS的终端之间的数据传输过程。二、实验任务…

【从零开始学Dify】大模型应用开发平台Dify本地化部署

目录Dify一、本地化部署1、安装docker2、安装Dify&#xff08;1&#xff09;拉取代码到本地&#xff08;2&#xff09;docker部署&#xff08;3&#xff09;查看服务状态&#xff08;4&#xff09;web端部署&#xff08;5&#xff09;登录二、可能会出现的问题&#xff08;1&am…

LVGL应用和部署(和物理按键交互)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】屏幕除了显示部分&#xff0c;还要去和其他外设进行交互&#xff0c;这是非常重要的一个处理方法。我们知道&#xff0c;不管是mcu&#xff0c;还是…

限流式保护器如何筑牢无人驾驶汽车充电站的安全防线

摘要&#xff1a; 随着新能源汽车&#xff0c;尤其是无人驾驶车队的快速发展&#xff0c;充电设施的安全可靠性至关重要。交流充电桩&#xff08;俗称“慢充桩”&#xff09;作为重要的充电基础设施&#xff0c;其末端回路的安全保护需满足国家标准GB51348-2019的严格要求&…

专题:2025母婴行业洞察报告|附60+份报告PDF汇总下载

原文链接&#xff1a;https://tecdat.cn/?p42908 全球母婴市场正经历结构性增长&#xff0c;一面是欧美成熟市场的品质消费升级&#xff0c;一面是东南亚、中东等新兴市场的人口红利释放。2020至2026年&#xff0c;全球母婴市场规模将从1859亿美元增至3084亿美元&#xff0c;年…

从零搭建多商户商城系统源码:技术栈、数据库设计与接口规划详解

如今&#xff0c;多商户商城系统已成为传统零售转型与新型电商平台构建的关键利器。无论是打造像某宝、某东这样的综合型平台&#xff0c;还是服务于垂直行业的独立电商&#xff0c;一套高效、可扩展的多商户商城系统源码&#xff0c;往往决定着平台的成败。 今天&#xff0c;小…

在Docker中运行macOS的超方便体验!

在数字化和开发人员快速迭代的今日&#xff0c;拥有一个便捷、高效的开发环境成为每个开发者梦寐以求的事情。特别是在需要操作多个系统、开发跨平台应用时&#xff0c;调试和测试的便利性显得尤为重要。今天为大家介绍的这款开源项目&#xff0c;正是一个解决此类问题的利器—…

Kettle导入Excel文件进数据库时,数值发生错误的一种原因

1、问题描述及原因 在使用kettle读取Excel文件、并导入数据库时&#xff0c;需要读取Excel中的数值、日期(或日期时间、时间)、文本这三种类型的列进来&#xff0c;发现读取其中的数值时&#xff0c;读取的数字就不对。 经调查&#xff0c;原因是&#xff0c;在“导出数据为E…

Windows安装DevEco Studio

1. 概述 DevEco Studio是华为基于IDEA Community开源工具开发的一站式HarmonyOS应用及元服务开发平台&#xff0c;为开发者提供代码开发、编译构建以及调测等功能 2. 运行环境要求 操作系统&#xff1a;Windows10 64位、Windows11 64位 内存&#xff1a;16GB及以上 硬盘&…

PLC框架-1.3.2 报文750控制汇川伺服的转矩上下限

本文介绍1200PLC如何使用750报文设定伺服转矩的上下限。 750号报文 PLC---->伺服 (控制) 伺服--->PLC (状态) PZD1

Redis知识集合---思维导图(持续更新中)

一、Redis中常见的数据类型有哪些&#xff1f;二、Redis为什么这么快&#xff1f;三、为什么Redis设计为单线程&#xff1f;6.0版本为何引入多线程&#xff1f;四、