Gin框架從入門到實戰:核心用法與最佳實踐

為什么選擇Gin框架?

Gin 是一個基于 Go 語言的高性能 Web 框架,具備以下優勢:

  • 輕量高效:底層依賴 net/http,性能接近原生。
  • 簡潔優雅:API 設計友好,支持路由分組、中間件鏈、參數綁定等特性。
  • 生態豐富:內置 JSON 解析、日志記錄、錯誤恢復等實用功能,社區插件生態完善。
  • 無論是構建 RESTful API 還是全棧應用,Gin 都能顯著提升開發效率。

安裝

要安裝Gin軟件包,您需要安裝Go并首先設置Go工作區。

  • 首先需要安裝Go(需要1.10+版本),然后可以使用下面的Go命令安裝Gin。
go get -u github.com/gin-gonic/gin
  • 將其導入您的代碼中:
import "github.com/gin-gonic/gin"

基礎示例

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {// 1.創建 (實例化gin.Engine結構體對象)r := gin.Default()// 2.綁定路由規則,執行的函數// gin.Context,封裝了request和responser.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Hello, Gin!")})// 3.監聽端口,默認在8080//  Run("里面不指定端口號默認為8080")r.Run(":8080")
}

運行后訪問 http://localhost:8080,即可看到返回的字符串。

Gin工工作作流流程

核心概念

  • Engine 容器對象,整個框架的基礎
  • Engine.tree 負責存儲路由和handle方法的映射,采用類似于字典樹的結構
  • Engine.RouterGroup 其中handlers存儲著所有中間件
  • Context 上下文對象,負責處理 請求回應 ,其中handles的存儲處理請求時中間件和處理方法的

在這里插入圖片描述

請求處理 流程

在這里插入圖片描述

GIN啟動流程

Gin初始化----> Use 中間件  ---->  注冊Routers路由 ----> RUN()啟動

Gin原原理解析

參考資料:http://v5blog.cn/pages/dd7d5a/

gin.Default()

Default()跟New()幾乎一模一樣, 就是調用了gin內置的Logger(), Recovery()中間件

// Default返回一個已經附加了Logger和Recovery中間件的Engine實例
func Default() *Engine {debugPrintWARNINGDefault()engine := New() "# 默認實例// 注冊中間建,中間件的是一個函數,最終只要返回一個 type HandlerFunc func(*Context) 就可以engine.Use(Logger(), Recovery()) // 默認注冊的兩個中間件return engine
}

engine := New() 初初始化始化

通過調用 gin.New() 方法來實例化 Engine容器

engine.Use() 注注冊冊中間件 中間件

在這里插入圖片描述

路由與參數處理

無參路由

func HelloWorldhandler(ctx *gin.Context){ctx.JSON(200, gin.H{"message": "Hello World",})
}func main() {// 創建一個默認的路由器router := gin.Default()// gin.Context是一個結構體,包含了請求和響應的細節, 封裝request和responserouter.GET("/",HelloWorldhandler)// 路由重定向router.GET("/re", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")})// 啟動服務器router.Run(":8081")
}

動態路由參數

通過 :param 捕獲 URL 中的變量:
(可以通過Context的Param方法來獲取API參數)

r.GET("/book/:id", func(c *gin.Context) {bookID := c.Param("id")c.String(http.StatusOK, "書籍ID: %s", bookID)
})

查詢參數

使用 Query 或 DefaultQuery 獲取 URL 參數:
http://127.0.0.1:8000/user?name=zhangsan

r.GET("/user", func(c *gin.Context) {name := c.Query("name")role := c.DefaultQuery("role", "guest")c.JSON(200, gin.H{"name": name, "role": role})
})

ShouldBind參數綁定

通過 ShouldBind 自動解析請求體(支持 JSON、Form 等):

我們可以基于請求的 Content-Type 識別請求數據類型并利用反射機制
自動提取請求中 QueryString 、 form表單 、 JSON 、 XML 等參數到結構體中

type LoginForm struct {Username string `form:"username" binding:"required"`Password string `form:"password" binding:"required"`
}r.POST("/login", func(c *gin.Context) {var form LoginFormif err := c.ShouldBind(&form); err != nil {c.JSON(400, gin.H{"error": err.Error()})return}c.String(200, "登錄成功: %s", form.Username)
})

完整代碼案例

package mainimport ("fmt""github.com/gin-gonic/gin""net/http"
)// HelloWorldhandler 無參數路由處理函數
func HelloWorldhandler(ctx *gin.Context){ctx.JSON(200, gin.H{"message": "Hello World",})
}func GetBookDetailHandler(ctx *gin.Context )  {bookId := ctx.Param("id")ctx.String(http.StatusOK, fmt.Sprintf("成功獲取書籍詳情:%s", bookId))}func GetUserDetailHandlers(ctx *gin.Context)   {username := ctx.Query("username")ctx.String(http.StatusOK, fmt.Sprintf("成功獲取用戶詳情:%s", username))
}type Login struct {Username string `form:"username" json:"username" binding:"required"`Password string `form:"password" json:"password" binding:"required"`
}func ResponseJsonHandler(c *gin.Context) {type Data struct {Msg string `json:"msg:"`Code int    `json:"code"`}d := Data{Msg: "success",Code: 200,}c.JSON(http.StatusOK, d)
}
func Loginhandler(c *gin.Context)  {var login Loginif err := c.ShouldBind(&login); err == nil {c.JSON(http.StatusOK, gin.H{"username": login.Username,"password": login.Password,})} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}func ResponseStringHandle(c *gin.Context)  {c.String(http.StatusOK, "Hello World")
}func main() {// 創建一個默認的路由器router := gin.Default()// gin.Context是一個結構體,包含了請求和響應的細節, 封裝request和response// 無參數路由router.GET("/",HelloWorldhandler)// 返回字符串router.GET("/string", ResponseStringHandle)// 返回jsonrouter.GET("/json", ResponseJsonHandler)// 動態路由參數router.GET("/book/:id", GetBookDetailHandler)// 查詢參數 Query 或 DefaultQueryrouter.GET("/user/", GetUserDetailHandlers)// 參數綁定router.POST("/login", Loginhandler)// 路由重定向router.GET("/re", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")})// 啟動服務器router.Run(":8081")
}

路由分發

為什么需要路由分發?

  • 我們一個項目有非常多的模塊,如果全部寫在一塊導致代碼結構混亂,不利于后續的擴展
  • 按照大的模塊,每個模塊有自己獨立的路由,主路由可以再main.go中進行注冊

項目結構

├── go.mod
├── go.sum
├── main.go
└── routers├── books.go└── users.go

main.go


import (
"days/routers"
"fmt"
"github.com/gin-gonic/gin"
)
func main() {router := gin.Default()// 全局中間件router.Use(MiddleWare())// 加載路由routers.LoadUsers(router)routers.LoadBooks(router)router.Run(":8081")
}

routers/users.go

package routers
import ("fmt""github.com/gin-gonic/gin""net/http""time"
)func LoadUsers(e *gin.Engine)  {e.GET("/user",MiddleWareOne(),UserHandler)
}func UserHandler(c *gin.Context) {fmt.Println("我是用戶路由")time.Sleep(time.Second * 5)c.JSON(http.StatusOK,gin.H{"message" : "weclome user",})
}

routers/books.go

package routers
import (
"net/http"
"github.com/gin-gonic/gin"
)
func LoadBooks(e *gin.Engine) {e.GET("/book", GetBookHandler)
}
func GetBookHandler(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "Book Router",})
}

在這里插入圖片描述

中間件

在這里插入圖片描述

  • Gin框架允許開發者在處理請求的過程中,加入用戶自己的鉤子(Hook)函數。
  • 這個鉤子函數就叫中間件,中間件適合處理一些公共的業務邏輯
  • 比如登錄認證、權限校驗、數據分頁、記錄日志、耗時統計等

全局中間件

func Logger() gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()c.Next()latency := time.Since(start)fmt.Printf("請求耗時: %v\n", latency)}
}func main() {r := gin.Default()r.Use(Logger()) // 全局生效r.GET("/", func(c *gin.Context) { /* ... */ })
}

局部中間件

func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {token := c.GetHeader("token")if token != "SECRET_KEY" {c.AbortWithStatusJSON(401, gin.H{"error": "身份驗證失敗"})}c.Next()}
}r.GET("/profile", AuthMiddleware(), func(c *gin.Context) {c.JSON(200, gin.H{"data": "用戶信息"})
})

next()方法

  • 在中間件中調用next()方法,會從next()方法調用的地方跳轉到Handler函數
  • Handler函數執行完成,若中間件還有部分代碼未執行(中間件中next()之后的代碼),則執行該代碼
    在這里插入圖片描述
package mainimport ("fmt""github.com/gin-gonic/gin""net/http""time"
)func main() {r := gin.Default()r.Use(Log(), RequestID())r.GET("/", func(c *gin.Context) {fmt.Println("app running  1")time.Sleep(time.Second * 5)c.String(http.StatusOK, "hello World!")})r.Run()
}
func Log() gin.HandlerFunc {return func(c *gin.Context) {fmt.Println("log start")c.Next()fmt.Println("log end")}
}
func RequestID() gin.HandlerFunc {return func(c *gin.Context) {fmt.Println("requestid start")c.Next()fmt.Println("requestid end")}
}

實現token認證

  • http://127.0.0.1:8080/index index首頁無需token直接訪問
  • http://127.0.0.1:8080/home home家目錄需要對token進行驗證,驗證通過才可訪問
package mainimport ("fmt""github.com/gin-gonic/gin"
)func AuthMiddleWare() func(c *gin.Context)  {return func(c *gin.Context){// 客戶端攜帶token 有三種方式 1.放在請求頭 2.放在請求體 3.放在url// token 驗證成功,返回 c.next()才會繼續,否則 c.Abort()token := c.Request.Header.Get("token")fmt.Println("獲取token:",token)if token == "" {c.JSON(200, gin.H{"code": 401,"msg": "身份驗證不通過",})c.Abort()}if token != "123456" {c.JSON(200, gin.H{"code": 401,"msg": "token錯誤",})c.Abort()}}
}func main()  {router := gin.Default()// 首頁無需驗證router.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{"message": "首頁",})})// Home頁面需要驗證router.GET("/home", AuthMiddleWare(), func(c *gin.Context) {c.JSON(200, gin.H{"message": "Home頁面",})})router.Run(":8081")
}

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/71311.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/71311.shtml
英文地址,請注明出處:http://en.pswp.cn/web/71311.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Leetcode 3468. Find the Number of Copy Arrays

Leetcode 3468. Find the Number of Copy Arrays 1. 解題思路2. 代碼實現 題目鏈接:3468. Find the Number of Copy Arrays 1. 解題思路 這一題的話思路上就是一個范圍考察,顯然,對于指定的copy方式,只要我們確定了第一個元素&…

VirtualBox虛擬機MacOS從Big Sur升級到Sequoia(失敗)

VirtualBox虛擬機里安裝好Big Sur版本,嘗試升級到Sequoia,但是最終失敗了。 軟件升級 直接在系統偏好-軟件更新里可以看到提示,提示可以升級到15版本Sequoia 點擊同意,看能不能升級到Sequoia吧。升級前先用時光做了備份。 升級…

[雜學筆記]HTTP1.0和HTTP1.1區別、socket系列接口與TCP協議、傳輸長數據的時候考慮網絡問題、慢查詢如何優化、C++的垃圾回收機制

目錄 1.HTTP1.0和HTTP1.1區別 2.socket系列接口與TCP協議 3.傳輸長數據的時候考慮網絡問題 4.慢查詢如何優化 5.C的垃圾回收機制 1.HTTP1.0和HTTP1.1區別 在連接方式上,HTTP1.0默認采用的是短鏈接的方式,就建立一次通信,也就是說即使在…

ANI AGI ASI的區別

??ANI、?AGI、?ASI的區別主要體現在定義、特點和應用場景上?: 1. ANI(狹義人工智能 Artificial narrow intelligence)?: ?定義?:ANI,也被稱為弱人工智能,是指專門設計用于執行特定任務…

用OpenCV寫個視頻播放器可還行?(Python版)

引言 提到OpenCV,大家首先想到的可能是圖像處理、目標檢測,但你是否想過——用OpenCV實現一個帶進度條、倍速播放、暫停功能的視頻播放器?本文將通過一個實戰項目,帶你深入掌握OpenCV的視頻處理能力,并解鎖以下功能&a…

leetcode日記(77)子集Ⅱ

不知道為什么看到這道題就很頭痛…… 其實只要掌握nums不包含重復元素的情況下的代碼就行了。 若nums不能包含重復元素&#xff0c;那么使用回溯很容易就能寫出來&#xff1a; class Solution {void hs(vector<int> v,int x,vector<int> r,vector<vector<…

通俗版解釋:分布式和微服務就像開餐廳

一、分布式系統&#xff1a;把大廚房拆成多個小廚房 想象你開了一家超火爆的餐廳&#xff0c;但原來的廚房太小了&#xff1a; 問題&#xff1a;一個廚師要同時切菜、炒菜、烤面包&#xff0c;手忙腳亂還容易出錯。 解決方案&#xff1a; 拆分成多個小廚房&#xff08;分布式…

StarRocks-fe工程在Cursor中不能識別為Java項目

SR簡介 StarRocks 是一款高性能分析型數據庫&#xff0c;支持實時、多維度、高并發的數據分析。本指南旨在解決在使用 VSCode 或 Cursor 開發 StarRocks 后端項目時遇到的模塊識別問題。 問題描述 使用 Cursor 或 VSCode 打開 StarRocks 的后端工程 fe 時&#xff0c;spark-…

第五節:基于Winform框架的串口助手小項目---串口收發《C#編程》

“路漫漫其修遠兮&#xff0c;吾將上下而求索” &#xff0c; -----------------------WHAPPY 目標任務&#xff1a; 1 從本地設備列表獲取串口。 RegistryKey keyCom Registry.LocalMachine.OpenSubKey("Hardware\DeviceMap\SerialComm"); RegistryKey 是.NET 框…

專題二最大連續1的個數|||

1.題目 題目分析&#xff1a; 給一個數字k&#xff0c;可以把數組里的0改成1&#xff0c;但是只能改k次&#xff0c;然后該變得到的數組能找到最長的子串且都是1。 2.算法原理 這里不用真的把0變成1&#xff0c;因為改了比較麻煩&#xff0c;下次用就要改回成1&#xff0c;這…

25年第四本【認知覺醒】

《認知覺醒》&#xff1a;一場與大腦的深度談判 在信息爆炸的焦慮時代&#xff0c;我們像被拋入湍流的溺水者&#xff0c;拼命抓取各種自我提升的浮木&#xff0c;卻在知識的漩渦中越陷越深。這不是一本簡單的成功學指南&#xff0c;而是一場關于人類認知系統的深度對話&#…

甘特圖開發代碼(測試版)

場景&#xff1a;要實現的功能就是單行數據能左右拖動。 流程五個&#xff1a;ABCDE。&#xff08;對應&#xff1a;Charter開發、概念和計劃、初樣開發、正樣開發、驗證&#xff09; 1、A有開始時間&#xff0c;結束時間。B的開始時間必須是A的結束時間&#xff08;相等或者…

服務器配置-從0到分析4:ssh免密登入

該部分涉及到公鑰、私鑰等部分knowledge&#xff0c;本人僅作嘗試 若將本地機器 SSH Key 的公鑰放到遠程主機&#xff0c;就能無需密碼直接遠程登錄遠程主機 1&#xff0c;在客戶端生成 ssh 公私鑰&#xff1a; 也就是我們本地機器&#xff0c;windows電腦 一路回車即可&am…

使用easyocr、PyPDF2對圖像及PDF文檔進行識別

一、概述 本 Python 腳本的主要功能是對當前目錄及其子目錄下的圖片和 PDF 文件進行光學字符識別&#xff08;OCR&#xff09;處理。它使用 easyocr 庫處理圖片中的文字&#xff0c;使用 PyPDF2 庫提取 PDF 文件中的文本&#xff0c;并將處理結果保存為文本文件。同時&#xff…

2000-2020年各省地方財政一般預算支出數據

2000-2020年各省地方財政一般預算支出數據 1、時間&#xff1a;2000-2020年 2、來源&#xff1a;國家統計局、統計年鑒 3、指標;行政區劃代碼、地區、年份、地方財政一般預算支出(億元) 4、范圍&#xff1a;31省 5、指標解釋&#xff1a;一般預算支出是國家對集中的預算收…

k8s 中各種發布方式介紹以及對比

前言 在 Kubernetes&#xff08;K8s&#xff09;中&#xff0c;不同的發布策略&#xff08;如金絲雀發布、灰度發布、藍綠發布等&#xff09;各有其適用場景和優缺點。 1. 滾動發布&#xff08;Rolling Update&#xff09; 核心原理&#xff1a;逐步替換舊版本 Pod 為新版本&…

力扣HOT100之哈希:1. 兩數之和

這道題之前刷代碼隨想錄的時候已經刷過好幾遍了&#xff0c;看到就直接秒了。這道題主要是通過unordered_map<int, int>來建立哈希表&#xff0c;其中鍵用來保存向量中的元素&#xff0c;而對應的值則為元素的下標。遍歷整個向量&#xff0c;當遍歷到nums[i]時&#xff0…

kakfa-3:ISR機制、HWLEO、生產者、消費者、核心參數負載均衡

1. kafka內核原理 1.1 ISR機制 光是依靠多副本機制能保證Kafka的高可用性&#xff0c;但是能保證數據不丟失嗎&#xff1f;不行&#xff0c;因為如果leader宕機&#xff0c;但是leader的數據還沒同步到follower上去&#xff0c;此時即使選舉了follower作為新的leader&#xff…

從小米汽車召回看智駕“命門”:智能化時代 — 時間就是安全

2025年1月&#xff0c;小米因車輛“授時同步異常”召回3萬余輛小米SU7&#xff0c;成為其造車歷程中的首個重大安全事件。 從小米SU7召回事件剖析&#xff0c;授時同步何以成為智能駕駛的命門&#xff1f; 2024年11月&#xff0c;多名車主反饋SU7標準版的智能泊車輔助功能出現…

FastGPT 引申:如何基于 LLM 判斷知識庫的好壞

文章目錄 如何基于 LLM 判斷知識庫的好壞方法概述示例 Prompt聲明抽取器 Prompt聲明檢查器 Prompt 判斷機制總結 下面介紹如何基于 LLM 判斷知識庫的好壞&#xff0c;并展示了如何利用聲明抽取器和聲明檢查器這兩個 prompt 構建評價體系。 如何基于 LLM 判斷知識庫的好壞 在知…