go go go 出發咯 - go web開發入門系列(二) Gin 框架實戰指南

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;四、