(Go Gin)Gin學習筆記(二):路由配置、基本路由、表單參數、上傳單個文件、上傳多個文件、淺扒路由原理

1. 路由

gin 框架中采用的路優酷是基于httprouter做的

HttpRouter 是一個高性能的 HTTP 請求路由器,適用于 Go 語言。它的設計目標是提供高效的路由匹配和低內存占用,特別適合需要高性能和簡單路由的應用場景。

主要特點

  • 顯式匹配:與其他路由器不同,HttpRouter 只支持顯式匹配,即一個請求只能匹配一個或不匹配任何路由。這避免了意外匹配,提高了 SEO 和用戶體驗。
  • 自動處理尾部斜杠:HttpRouter 會自動重定向缺少或多余尾部斜杠的請求,前提是新路徑有處理程序。如果不需要這種行為,可以關閉2。
  • 路徑自動校正:除了處理尾部斜杠,HttpRouter 還可以修正錯誤的大小寫和多余的路徑元素(如 …///)。
  • 路由參數:支持在路由模式中使用命名參數和捕獲所有參數,簡化了 URL 路徑的解析。
  • 零垃圾:匹配和分發過程不會產生垃圾,只有在路徑包含參數時才會進行堆分配。
  • 最佳性能:使用壓縮動態 trie(基數樹)結構進行高效匹配,性能優異。

1.1 基本路由

package oneimport ("github.com/gin-gonic/gin""net/http"
)func index() {r := gin.Default()r.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Hello Gin")})r.POST("/", func(c *gin.Context) {})r.DELETE("/", func(c *gin.Context) {})r.PUT("/", func(c *gin.Context) {})r.Run(":8081")
}
  • gin支持Restful風格的API
  • 即Representational State Transfer的縮寫。直接翻譯的意思是"表現層狀態轉化",是一種互聯網應用程序的API設計理念:URL定位資源,用HTTP描述操作

1.獲取文章:/blog/getXxx Get blog/Xxx

2.添加:/blog/addXxx POST blog/Xxx

3.修改:/blog/updateXxx PUT blog/Xxx

4.刪除:/blog/delXxxx DELETE blog/Xxx

另一種方式

package mainimport ("github.com/gin-gonic/gin""net/http"
)func sayHello(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "hello",})
}func main() {r := gin.Default()r.GET("/test1", sayHello)r.Run(":8080")
}

1.2 API 參數

請求方式的方法可以通過函數來接受,從而獲得請求傳來的參數

package mainimport ("github.com/gin-gonic/gin""net/http"
)func sayHello(c *gin.Context) {name := c.Param("name")age := c.Param("age")c.JSON(http.StatusOK, gin.H{"name": name,"age":  age,})
}func main() {r := gin.Default()// 請求:localhost/test1/xxx/ooo// 響應:{"name":xxx,"age":ooo}r.GET("/test1/:name/:age", sayHello)r.Run(":8080")
}

需要注意:gin默認開啟restful風格語法,所以可以直接在請求路徑上添加名稱,屬性名是擬定在請求的路徑上的

r.GET("/test1/:name/:age", sayHello)

這里請求路徑擬定了方法內 c *gin.Context 中的參數名稱;這里默認有 name 和 age 屬性

請求:http://localhost:8080/test1/張三/18

響應結果:

{"age": "18","name": "張三"
}

1.3 URL 參數

路徑參數,就不會使用restful風格語法進行接受請求參數

package mainimport ("fmt""github.com/gin-gonic/gin""net/http"
)func sayHello(c *gin.Context) {// Query方法,若不存在則返回空字符串name := c.Query("name")age := c.Query("age")fmt.Println("========================")fmt.Println("名稱", name)fmt.Println("年齡", name)fmt.Println("========================")name1 := c.DefaultQuery("name", "默認名稱")fmt.Println("defaultName", name1)c.JSON(http.StatusOK, gin.H{"name":  name,"age":   age,"name1": name1,})
}func main() {r := gin.Default()// 請求:localhost/test1/?xxx=xxx&ooo=000// 響應:{"name":xxx,"age":ooo}r.GET("/test1", sayHello)r.Run(":8080")
}
  • URL參數可以通過DefaultQuery()或Query()方法獲取
  • DefaultQuery()若參數不存在,返回默認值,Query()若不存在,返回空串

兩種請求:

  • 請求1:http://localhost:8080/test1?age=19

  • 響應數據1:

{"age": "19","name": "","name1": "默認名稱"
}
  • 請求2:http://localhost:8080/test1?name=張三&age=19
  • 響應數據2:
{"age": "19","name": "張三","name1": "張三"
}

1.4 表單參數

  • 表單傳輸為post請求,http常見的傳輸格式為四種:
    • application/json
    • application/x-www-form-urlencoded
    • application/xml
    • multipart/form-data
  • 表單參數可以通過PostForm()方法獲取,該方法默認解析的是x-www-form-urlencoded或from-data格式的參數

測試的html文件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body>
<form action="http://localhost:8080/form" method="post" action="application/x-www-form-urlencoded">用戶名:<input type="text" name="username" placeholder="請輸入你的用戶名">  <br>&nbsp;&nbsp;&nbsp;碼:<input type="password" name="user_password" placeholder="請輸入你的密碼">  <br><input type="submit" value="提交">
</form>
</body>
</html>
  • index.go
package mainimport ("github.com/gin-gonic/gin""net/http"
)func sayHello(c *gin.Context) {types := c.DefaultPostForm("type", "post")// 接受參數name := c.PostForm("username") // 對應頁面傳入的name值或者json的屬性password := c.PostForm("user_password")c.JSON(http.StatusOK, gin.H{"types":    types,"name":     name,"password": password,})
}func main() {r := gin.Default()r.POST("/form", sayHello)r.Run(":8080")
}

返回數據:

{"name": "rx","password": "123","types": "post"
}

1.5 上傳單個文件

  • multipart/form-data格式用于文件上傳
  • gin文件上傳與原生的net/http方法類似,不同在于gin把原生的request封裝到c.Request中

demo2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">上傳文件:<input type="file" name="file" ><input type="submit" value="提交">
</form>
</body>
</html>
  • index.go
package __single_fileimport ("github.com/gin-gonic/gin""net/http"
)func DefaultFunction(c *gin.Context) {// 上傳單個文件file, _ := c.FormFile("file")if file == nil {c.JSON(http.StatusInternalServerError, gin.H{"code":    http.StatusInternalServerError,"message": "文件為空",})return}c.SaveUploadedFile(file, file.Filename)c.JSON(http.StatusOK, gin.H{"file": file.Filename,})
}func main() {r := gin.Default()r.POST("/upload", DefaultFunction)r.Run(":8080")
}

數據響應:

{"file":"Picture3.png"}

1.6 上傳單個文件——添加限制

package __single_file_restrictimport ("fmt""github.com/gin-gonic/gin""log""net/http"
)func DefaultFunction(c *gin.Context) {// 上傳單個文件_攜帶限制_, file, err := c.Request.FormFile("file")if err != nil {log.Printf("Error when try to get file: %v", err)}//file.Size 獲取文件大小if file.Size > 1024*1024*2 {fmt.Println("文件太大了")return}//file.Header.Get("Content-Type")獲取上傳文件的類型if file.Header.Get("Content-Type") != "image/png" {fmt.Println("只允許上傳png圖片")return}c.SaveUploadedFile(file, file.Filename)c.JSON(http.StatusOK, gin.H{"file": file.Filename,})
}func main() {r := gin.Default()r.POST("/upload", DefaultFunction)r.Run(":8080")
}

數據響應:

{"file":"Picture3.png"}

1.7 上傳多個文件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body><form action="http://localhost:8000/upload" method="post" enctype="multipart/form-data">上傳文件:<input type="file" name="files" multiple><input type="submit" value="提交"></form>
</body>
</html>
package mainimport ("github.com/gin-gonic/gin""net/http""fmt"
)// gin的helloWorldfunc main() {// 1.創建路由// 默認使用了2個中間件Logger(), Recovery()r := gin.Default()// 限制表單上傳大小 8MB,默認為32MBr.MaxMultipartMemory = 8 << 20r.POST("/upload", func(c *gin.Context) {form, err := c.MultipartForm()if err != nil {c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))}// 獲取所有圖片files := form.File["files"]// 遍歷所有圖片for _, file := range files {// 逐個存if err := c.SaveUploadedFile(file, file.Filename); err != nil {c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))return}}c.String(200, fmt.Sprintf("upload ok %d files", len(files)))})//默認端口號是8080r.Run(":8000")
}

1.8 路由組-routers group

package mainimport ("github.com/gin-gonic/gin""net/http"
)func cat(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"cat": c.Query("cat"),})
}func dog(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"dog": c.Query("dog"),})
}func main() {r := gin.Default()animal := r.Group("/animal")// http://localhost:8080/animal/cat?cat=tomanimal.GET("/cat", cat)animal.GET("/dog", dog)// 第二種寫法// http://localhost:8080/animal2/cat?cat=tomanimal2 := r.Group("/animal2"){animal2.GET("/cat", cat)animal2.GET("/dog", dog)}r.Run(":8080")
}

路由組有兩種寫法

  • 動態配置,將變量聲明出來可以在任意位置配置路由

    animal := r.Group("/animal")
    // http://localhost:8080/animal/cat?cat=tom
    animal.GET("/cat", cat)
    animal.GET("/dog", dog)
    
  • 對象配置,直接使用對象進行配置

    // http://localhost:8080/animal2/cat?cat=tom
    animal2 := r.Group("/animal2")
    {animal2.GET("/cat", cat)animal2.GET("/dog", dog)
    }
    

注意路由組配置:組路徑下的請求配置,必須加上 / 例如: animal2.GET(“/cat”, cat)

1.9 httprotuer路由原理

1.9.1 Radix Tree(壓縮前綴樹)

基數樹(Radix Tree)又稱為PAT位樹(Patricia Trie or crit bit tree),是一種更節省空間的前綴樹(Trie Tree)。對于基數樹的每個節點,如果該節點是唯一的子樹的話,就和父節點合并

在這里插入圖片描述

Radix Tree可以被認為是一棵簡潔版的前綴樹。其注冊路由的過程就是構造前綴樹的過程,具有公共前綴的節點也共享一個公共父節點。假設注冊以下路由信息:

r := gin.Default()r.GET("/", func1)
r.GET("/search/", func2)
r.GET("/support/", func3)
r.GET("/blog/", func4)
r.GET("/blog/:post/", func5)
r.GET("/about-us/", func6)
r.GET("/about-us/team/", func7)
r.GET("/contact/", func8)

生成的路由樹信息如下:

Priority   Path             Handle
9          \                *<1>
3          ├s               nil
2          |├earch\         *<2>
1          |└upport\        *<3>
2          ├blog\           *<4>
1          |:post      nil
1          |         └\     *<5>
2          ├about-us\       *<6>
1          |        └team\  *<7>
1          └contact\        *<8>

最右列每個***<數字>表示Handle處理函數的內存地址(一個指針)**。

  • 從根節點遍歷到葉子節點就能得到完整的路由表。

例如:blog/:post其中:post只是實際文章名稱的占位符(參數)。

與hash-maps不同,Radix Tree結構還允許使用像:post參數這種動態部分,因為Radix Tree實際上是根據路由模式進行匹配,而不僅僅是比較哈希值。

由于URL路徑具有層次結構,并且只使用有限的一組字符(字節值),所以很可能有許多常見的前綴。這使開發者可以很容易地將路由簡化為更小的問題。

  • 此外,路由器為每種請求方法管理一棵單獨的樹。
  • 一方面,它比在每個節點中都保存一個method-> handle map更加節省空間,而且還使開發者甚至可以在開始在前綴樹中查找之前大大減少路由問題。

為了獲得更好的可伸縮性,每個樹級別上的子節點都按Priority(優先級)排序,其中優先級(最左列)就是在子節點(子節點、子子節點等等)中注冊的句柄的數量。

這樣做有兩個好處:

  1. 優先匹配被大多數路由路徑包含的節點。這樣可以讓盡可能多的路由快速被定位。
  2. 類似于成本補償。最長的路徑可以被優先匹配,補償體現在最長的路徑需要花費更長的時間來定位,如果最長路徑的節點能被優先匹配(即每次拿子節點都命中),那么路由匹配所花的時間不一定比短路徑的路由長。

下面展示了節點(每個-可以看做一個節點)匹配的路徑:從左到右,從上到下。

-----------------------------------

1.9.2 httproute 特點

路由器支持路由模式中的變量,并與請求方法進行匹配。其伸縮性相較于原生net/http庫更好。

明確的路由匹配,一個path對應一個Handler。

不用關心/,例如當請求/foo/時,此path不存在,如果有/foo會自動302轉發

path自動修正,例如//foo轉化成/foo

httprouter使用的數據結構就是壓縮字典樹。

典型的壓縮字典樹結構如下:

在這里插入圖片描述

1.9 參考文章:gin框架httprouter路由原理

2. ??GoGin框架——前文鏈接

Gin框架學習參考網站:gin框架·Go語言中文文檔

(Go Gin)基于Go的WEB開發框架,GO Gin是什么?怎么啟動?本文給你答案

3. 💕👉博客專欄

  • Golang專欄-包含基礎、Gin、Goam等知識
  • 云原生專欄-包含k8s、docker等知識
  • 從0開始學習云計算-華為HCIP證書
  • JUC專欄-帶你快速領悟JUC的知識!
  • JVM專欄-深入Java虛擬機,理解JVM的原理
  • 基于Java研究 數據結構與算法-包含貪心算法、加權圖、最短路徑算法等知識
  • Docker專欄-上手熱門容器技術Docker
  • SpringBoot專欄-學習SpringBoot快速開發后端
  • 項目管理工具的學習-設計技術:Maven、Git、Gradle等相關管理工具
  • JavaSE-全面了解Java基礎
  • JS專欄-使用JS作的一部分實例~
  • 使用CSS所作的一部分案例

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

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

相關文章

Linux下的好玩的命令

在 CentOS 下&#xff0c;有許多有趣且實用的 Linux 命令&#xff0c;可以幫助你更好地了解系統、提升效率或進行娛樂。以下是一些好玩的 Linux 命令及其說明&#xff1a; 1. cowsay 和 cowthink 功能&#xff1a;讓一只牛&#xff08;或其他動物&#xff09;說出你想說的話。…

OpenharmonyOS+RK3568,【編譯燒錄】

文章目錄 1. 摘要 ?2. 代碼下載 &#x1f4e9;3. 編譯 &#x1f5a5;?4. 修改&適配 ??4.1 編譯框架基本概念4.2 vendor & device 目錄4.3 內核編譯4.3.1 如何修改、適配自己的開發板&#xff1f; 4.4 修改外設驅動 5. 燒錄&驗證 &#x1f4cb;參考 1. 摘要 ? …

深度學習模型優化:如何讓數據科學更智能?

深度學習模型優化:如何讓數據科學更智能? 一、引言:為什么優化深度學習模型如此重要? 深度學習的應用已經滲透到數據科學的各個領域,從圖像識別到自然語言處理,從推薦系統到金融風控,每一個智能模型都依賴于數據驅動的訓練。然而,一個模型的性能不僅僅取決于其架構,…

學習Python的第二天之網絡爬蟲

30歲程序員學習Python的第二天之網絡爬蟲的信息提取 BeautifulSoup庫 地址&#xff1a;https://beautifulsoup.readthedocs.io/zh-cn/v4.4.0/ 1、BeautifulSoup4安裝 在windows系統下通過管理員權限運行cmd窗口 運行pip install beautifulsoup4 測試實例 import requests…

n8n 鍵盤快捷鍵和控制鍵

n8n 鍵盤快捷鍵和控制鍵 工作流控制鍵畫布操作移動畫布畫布縮放畫布上的節點操作選中一個或多個節點時的快捷鍵 節點面板操作節點面板分類操作 節點內部操作 n8n 為部分操作提供了鍵盤快捷鍵。 工作流控制鍵 Ctrl Alt n&#xff1a;創建新工作流Ctrl o&#xff1a;打開工作…

keil+vscode+騰訊ai助手

嵌入式軟件開發 這個是之前一直想寫的開發方式&#xff0c;不過上份工作一直在忙&#xff0c;沒有抽出時間花在上面&#xff0c;現在空下來好好寫一寫吧&#xff01;標題軟件安裝 關于VSCode以及Keil的安裝可以在以下鏈接中點擊瀏覽 VSCode安裝 Keil5安裝 CubeMx安裝 插件下…

Unity教程(二十三)技能系統 投劍技能(上)基礎實現

Unity開發2D類銀河惡魔城游戲學習筆記 Unity教程&#xff08;零&#xff09;Unity和VS的使用相關內容 Unity教程&#xff08;一&#xff09;開始學習狀態機 Unity教程&#xff08;二&#xff09;角色移動的實現 Unity教程&#xff08;三&#xff09;角色跳躍的實現 Unity教程&…

Oracle01-入門

零、文章目錄 Oracle01-入門 1、Oracle簡介 &#xff08;1&#xff09;數據庫基礎 數據庫基礎請參考&#xff1a;https://blog.csdn.net/liyou123456789/article/details/131207068 &#xff08;2&#xff09;Oracle是什么 ORACLE 數據庫系統是美國 ORACLE 公司&#xff…

springboot集成mybatis-plus詳細使用

以下是 Spring Boot 集成 MyBatis-Plus 的詳細步驟&#xff1a; 創建 Spring Boot 項目 可使用 Spring Initializr 快速創建項目&#xff0c;添加相關依賴。 引入依賴 在項目 pom.xml 文件中添加以下依賴&#xff1a; <!-- MyBatis-Plus 啟動依賴 --> <dependenc…

【wsl】命令說明,wsl的虛擬機ubuntu十分好用

wsl官方說明地址 wsl虛擬機安裝簡單方便&#xff0c;十分推薦。 安裝 在上方的官網鏈接有安裝辦法和各種操作指南&#xff0c;在此不再贅述。 安裝wsl后從微軟商店搜索ubuntu點擊后就能直接安裝虛擬機鏡像&#xff0c;多快好省。 wsl命令 閱讀官網文檔時發現wsl十分強大 …

Open CASCADE學習|判斷一點與圓弧的位置關系

一、引言 在計算機輔助設計&#xff08;CAD&#xff09;、計算機圖形學以及機械制造等眾多領域中&#xff0c;經常需要處理幾何圖形之間的位置關系判斷問題。其中&#xff0c;判斷一個點與圓弧的位置關系是一個基礎且重要的任務。Open CASCADE 作為一個強大的開源幾何建模內核…

<論文>(字節跳動)使用大語言模型進行時間序列理解和推理

一、摘要 本文介紹2024年12月字節跳動牽頭發表的大模型論文《ChatTS: Aligning Time Series with LLMs via Synthetic Data for Enhanced Understanding and Reasoning》。論文提出了 ChatTS 模型&#xff0c;用合成數據提升對時間序列的理解和推理能力。作者在紐約出租車乘客數…

大數據應用開發和項目實戰-電商雙11美妝數據分析

數據初步了解 &#xff08;head出現&#xff0c;意味著只出現前5行&#xff0c;如果只出現后面幾行就是tail&#xff09; info shape describe 數據清洗 重復值處理 這個重復值是否去掉要看實際情況&#xff0c;比如說&#xff1a;昨天賣了5瓶七喜&#xff0c;今天賣了5瓶七…

Vi/Vim 編輯器詳細指南

Vi/Vim 編輯器詳細指南 簡介一、模式詳解1. 命令模式(Normal Mode)2. 插入模式(Insert Mode)3. 可視模式(Visual Mode)4. 命令行模式(Ex Mode)二、核心操作1. 保存與退出2. 導航與移動3. 編輯與文本操作4. 搜索與替換三、高級技巧1. 多文件與窗口操作2. 宏錄制3. 寄存器…

kotlin 01flow-StateFlow 完整教程

一 Android StateFlow 完整教程&#xff1a;從入門到實戰 StateFlow 是 Kotlin 協程庫中用于狀態管理的響應式流&#xff0c;特別適合在 Android 應用開發中管理 UI 狀態。本教程將帶全面了解 StateFlow 的使用方法。 1. StateFlow 基礎概念 1.1 什么是 StateFlow? StateF…

開發搭載OneNet平臺的物聯網數據收發APP的設計與實現

一、開發環境與工具準備 工具安裝 下載HBuilderX開發版(推薦使用開發版以避免插件兼容性問題)安裝Node.js和npm(用于依賴管理及打包)配置Android Studio(本地打包需集成離線SDK)項目初始化 創建uni-app項目,選擇“默認模板”或“空白模板”安裝必要的UI庫(如uView或Van…

HHsuite3 的 HHblits 和 HHsearch比較

HHblits 與 HHsearch 的核心區別及遠源同源檢測能力對比 一、核心功能與定位差異 特征HHblitsHHsearch核心目標快速迭代搜索,構建高質量多序列比對(MSA)和 Profile HMM,用于大規模序列聚類與初步同源篩選。高精度 Profile HMM-HMM 比對,用于深度同源檢測與結構 / 功能預測…

【從零開始學習RabbitMQ | 第二篇】生成交換機到MQ的可靠性保障

目錄 ?編輯前言 交換機 Direct交換機與Fanout交換機的差異 Topic交換機 Topic交換機相比Direct交換機的差異 生成我們的交換機&#xff0c;隊列&#xff0c;以及綁定關系 基于代碼去生成交換機和隊列 基于注解去聲明隊列和交換機 消息轉換器 消息隊列的高可靠性 發送…

LeetCode 熱題 100 22. 括號生成

LeetCode 熱題 100 | 22. 括號生成 大家好&#xff0c;今天我們來解決一道經典的算法題——括號生成。這道題在 LeetCode 上被標記為中等難度&#xff0c;要求生成所有可能的并且有效的括號組合。這是一道非常經典的回溯法題目&#xff0c;非常適合用來練習遞歸和回溯的技巧。…

TestStand API 簡介

TestStand API 簡介 在自動化測試領域&#xff0c;TestStand 憑借其靈活的架構和強大的功能&#xff0c;成為眾多開發者的首選工具。而 TestStand API&#xff08;Application Programming Interface&#xff0c;應用程序編程接口&#xff09;則是打開 TestStand 強大功能的 “…