目錄
??前言
1.什么是前端?什么是后端?🌀
2.Gin框架介紹?🌷
3.Gin框架的基本使用 -Hello,World例子🌷
?🌿入門示例 - Hello,World
💻補充(一些常用的網絡術語):?
3.1 Get請求與Post請求📞
3.2 狀態碼?🔧
4.Gin的各類返回方式?🌷
??返回字符串:
???返回xml:
??返回文件(如Excel,txt,png等文件):
???頁面重定向:
?5.如何處理前端的請求數據🌷
6.Gin框架實戰案例 -表單信息提交處理🌷
4.1 前端JS請求?🔅
4.2?后端Gin編寫?🔅?
??前言
? ? ? ? 通過前面的基本學習,終于開始進入項目學習階段。本文將主要介紹Go語言官方的后端框架Gin如何與前端數據交互,以及實現最基本的表單數據交互案例,而關于后端操作數據庫的部分,將留在下一章進行詳細講解。
1.什么是前端?什么是后端?🌀
????????前端和后端是軟件開發中的兩個重要部分,它們共同協作完成一個完整的產品或系統。通俗來說,前端就像餐廳的前臺,負責接待顧客、展示菜單、處理顧客的點餐需求,后端就像餐廳的后廚,負責準備食材、烹飪菜肴、確保菜品按時送到前臺,前端是用戶看到的“表面”,負責展示和交互。后端是用戶看不到的“幕后”,負責處理數據和邏輯。
對比維度 | 前端 | 后端 |
---|---|---|
定義 | 前端是用戶直接看到和交互的部分,主要負責展示界面和處理用戶操作。 | 后端是運行在服務器上的部分,主要負責數據處理、邏輯運算和存儲。 |
主要功能 | 展示頁面、交互設計、響應用戶操作(如點擊按鈕、輸入內容)。 | 處理業務邏輯、管理數據庫、提供 API 接口給前端調用。 |
技術棧 | HTML、CSS、JavaScript、框架(如 React、Vue、Angular)。 | 服務器語言(如 Python、Java、Node.js、PHP)、 數據庫(如 MySQL、MongoDB)。 |
工作內容 | 設計和實現用戶界面、優化用戶體驗、與后端 API 交互。 | 開發服務器端邏輯、管理數據庫、處理數據、提供安全性和性能優化。 |
用戶體驗 | 直接影響用戶對產品的第一印象,注重界面美觀和交互流暢性。 | 間接影響用戶體驗,主要通過提供穩定、快速的服務來支持前端。 |
安全性 | 前端代碼是公開的,容易被用戶查看和篡改,安全性較弱。 | 后端代碼運行在服務器上,用戶無法直接訪問,安全性較高。 |
開發工具 | 瀏覽器、代碼編輯器(如 VS Code)、前端框架工具。 | 服務器環境、數據庫管理工具、API 測試工具(如 Postman)。 |
2.Gin框架介紹?🌷
????????Gin 是一個用 Go 語言編寫的高性能 HTTP Web 框架,以輕量級、快速路由和中間件支持著稱。Gin的設計目標是幫助開發者快速構建Web應用和RESTful API,同時保持高性能和低資源占用。其主要特點如下:
- 高性能:基于Radix樹的路由實現,內存占用小,無反射,API性能可預測。
- 零分配路由器:路由處理過程中不產生內存分配,確保高效。
- 中間件支持:支持鏈式中間件,可以用于日志記錄、認證、GZIP壓縮等。
- 崩潰恢復:能夠捕獲HTTP請求中的panic并恢復,確保服務器始終可用。
- JSON驗證:支持對請求中的JSON數據進行驗證,確保數據完整性。
- 路由分組:支持路由分組,便于組織不同功能的API版本或權限。
- 錯誤管理:提供方便的方式收集和處理HTTP請求中的錯誤。
- 內置渲染:支持JSON、XML和HTML的渲染。
- 可擴展性:易于創建自定義中間件,滿足特定需求
同樣Go語言的后端框架不止Gin一種,還有其它后端框架,如Beggo,比較結果如下:
框架 | 性能 | 路由 | 中間件 | 適用場景 | 學習曲線 |
---|---|---|---|---|---|
Gin | 極高 | 基于httprouter | 豐富且靈活 | API服務、微服務、高性能后端 | 低 |
Echo | 高 | 自定義實現 | 簡潔 | RESTful API、輕量級應用 | 低 |
Fiber | 極高 | 類似Express | Express風格 | 替代Gin,追求極簡語法 | 中 |
Beego | 中等 | 自帶MVC路由 | 全功能 | 全棧開發(含ORM、模板引擎) | 中高 |
3.Gin框架的基本使用 -Hello,World例子🌷
? ? ? ? 首先我們得先導入Gin的包,熟悉python語言的同學都知道,對于 python 我們可以在終端使用 pip install 命令進行下載所需要的包,而go語言,可以在終端使用 go get 命令來獲取第三方包,導入到項目中。我們在項目的終端中,輸入如下命令,即可將Gin框架導入到項目中,接下來就可以使用Gin框架進行開發了。
$ go get -u github.com/gin-gonic/gin
?🌿入門示例 - Hello,World
package mainimport "github.com/gin-gonic/gin" // 導入Gin的包func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{"message": "Hello, World!"})})r.Run(":8080") // 監聽 0.0.0.0:8080
}
?🌳解釋🌳:
- r := gin.Default() 使用gin創建了一個默認的路由器實例,它會自動加載一些中間件,比如日志記錄和恢復中間件,接下來由它負責處理網頁的HTTP請求并調用相應的處理函數。
- r.get用于定義一個GET請求的路由。這里定義了一個路徑為
"/"
的GET請求處理函數。當客戶端訪問應用的根路徑"/"
時,會調用這個處理函數。c
是gin.Context
類型的參數,它包含了請求和響應的所有信息。c.JSON
用于向客戶端發送JSON格式的響應。200
是HTTP狀態碼,表示請求成功。gin.H
是一個快捷方式,用于創建一個map[string]interface{}
,這里用于構建JSON響應內容。
r.Run()
啟動HTTP服務器并開始監聽請求。":8080"
指定了服務器監聽的端口號為8080
? ? ? ? ?通過本次簡單的例子,我們可以歸納出更為普遍的Gin后端框架處理流程,如下圖所示:
💻補充(一些常用的網絡術語):?
3.1 Get請求與Post請求📞
? ? ? ? 通俗來說,GET請求就像去圖書館借書,你告訴圖書館員你想借的書名(參數),這個書名會顯示在借書單上(URL),別人可以看到。POST請求就像去圖書館還書,你把書交給圖書館員(數據放在請求體中),這個過程是相對私密的,別人不會知道你具體還了什么書。
對比維度 | GET請求 | POST請求 |
---|---|---|
用途 | 用于從服務器獲取數據,比如訪問一個網頁或查詢信息。 | 用于向服務器提交數據,比如提交表單或上傳文件。 |
數據傳遞方式 | 參數附加在URL后面,比如http://example.com/search?q=keyword 。 | 數據放在請求體中,不會顯示在URL中。 |
安全性 | 相對不安全,因為參數會顯示在瀏覽器地址欄中,可能會被保存在瀏覽器歷史記錄或服務器日志中。 | 相對更安全,因為數據不會顯示在瀏覽器地址欄中,也不容易被緩存或記錄在歷史中。 |
限制 | URL長度有限制,通常不能超過2048個字符,不適合傳遞大量數據。 | 沒有長度限制,可以傳遞大量數據。 |
緩存 | 可以被瀏覽器緩存,多次訪問相同的URL時可能不會每次都向服務器發送請求。 | 通常不會被瀏覽器緩存,每次提交都會向服務器發送請求。 |
冪等性 | 是冪等的,多次請求相同URL不會產生不同結果。 | 不是冪等的,多次提交相同數據可能會產生不同結果(如多次提交表單)。 |
書簽 | 可以通過書簽保存URL,方便后續訪問。 | 不能通過書簽保存請求體中的數據。 |
適用場景 | 適合簡單的查詢和數據獲取,比如搜索、查看頁面內容。 | 適合復雜操作和敏感數據的提交,比如登錄、文件上傳、表單提交等。 |
3.2 狀態碼?🔧
????????HTTP狀態碼是服務器對客戶端請求的響應狀態的三位數字代碼,用于表示請求的處理結果。狀態碼分為以下幾類:
-
1xx(信息性狀態碼):表示請求已接收,正在處理。
-
2xx(成功狀態碼):表示請求已成功處理。
-
3xx(重定向狀態碼):表示需要進一步操作才能完成請求。
-
4xx(客戶端錯誤狀態碼):表示客戶端請求有誤,服務器無法處理。
-
5xx(服務器錯誤狀態碼):表示服務器處理請求時發生錯誤。
狀態碼 | 描述 |
---|---|
100 | 繼續,表示服務器已收到請求的初始部分,客戶端可以繼續發送其余請求。 |
200 | 請求成功,服務器返回了請求的數據。 |
201 | 資源已成功創建。 |
301 | 資源的URL已永久更改。 |
302 | 資源的URL暫時更改。 |
400 | 請求有誤,服務器無法處理。 |
401 | 請求未授權。 |
403 | 請求被拒絕。 |
404 | 請求的資源不存在。 |
500 | 服務器內部錯誤,無法完成請求。 |
502 | 服務器從上游服務器接收到的響應無效。 |
503 | 服務不可用,通常是服務器過載或維護 |
????????而在Go語言中,可以使用net/http包來處理HTTP請求和響應,如http.StatusOK代表狀態碼200,http.StatusBadRequest代表狀態碼400,http.StatusInternalServerError代表狀態碼500
4.Gin的各類返回方式?🌷
? ? ? ? 上述基本案例中,Gin返回的數據類型為json格式,下面介紹一些別的格式的數據返回。
??返回字符串:
router.GET("/str", func(c *gin.Context) {c.String(http.StatusOK, "返回成功")
})
???返回xml:
router.GET("/xml", func(c *gin.Context) {c.XML(http.StatusOK, gin.H{"user": "FJNU", "message": "hey", "status": http.StatusOK})
})
??返回文件(如Excel,txt,png等文件):
router.GET("/download/:filename", func(c *gin.Context) {filename := c.Param("filename") // 獲取前端傳輸的文件名filePath := "./files/" + filename // 獲取本地的文件路徑c.File(filePath) // 將對應的文件傳回前端})
? ? ? ? 上述方法用于返回單個文件,filename必須包含文件的擴展名(如.png),Gin會自動根據文件擴展名設置正確的MIME類型。
????????如果希望文件被瀏覽器作為附件下載而不是直接顯示,可以使用c.FileAttachment()
方法。
package mainimport "github.com/gin-gonic/gin"func main() {router := gin.Default()router.GET("/download/:filename", func(c *gin.Context) {filename := c.Param("filename")filePath := "./files/" + filenamec.FileAttachment(filePath, filename)})router.Run(":8080")
}
???頁面重定向:
? ? ? ? 如果你希望點擊某個按鈕后,跳轉到另一個頁面,可以使用以下方法:
router.GET("/redirect", func(c *gin.Context) {//支持內部和外部的重定向c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
})
?5.如何處理前端的請求數據🌷
????????c *gin.Context 是 Gin 框架處理 HTTP 請求的核心對象,封裝了請求和響應的所有操作。以下是其核心功能及用法:
功能 | 方法/屬性 | 說明 |
---|---|---|
獲取請求參數 | c.Param("key") | 獲取路由參數(如?/user/:id ?→?id ) |
c.Query("key") | 獲取 URL 查詢參數(如??name=John ) | |
c.PostForm("key") | 獲取表單數據(Content-Type: application/x-www-form-urlencoded ) | |
c.FormFile("file") | 獲取上傳的文件(Content-Type: multipart/form-data ) | |
請求頭操作 | c.GetHeader("User-Agent") | 獲取請求頭字段 |
c.Request.Header | 直接訪問原始請求頭(http.Header 類型) |
1.獲取路由當中的靜態值(Query):
r.GET("/test/:age", func(c *gin.Context) {age := c.Query("age")c.String(200, "I am %s years old", age)})
2.獲取動態路由中的值(Param):
r.GET("/hello/:name", func(c *gin.Context) {name := c.Param("name")c.String(200, "hello %s", name)})
?3.保存前端所上傳的文件(如word,excel,png圖片等):
r := gin.Default()// 設置靜態文件目錄,方便前端訪問上傳的文件r.Static("/uploads", "./uploads")// 處理文件上傳r.POST("/upload", func(c *gin.Context) {// 獲取名為 "file" 的上傳文件file, err := c.FormFile("file")if err != nil {c.String(http.StatusBadRequest, fmt.Sprintf("get form file err: %s", err.Error()))return}// 獲取上傳文件的原始文件名filename := file.Filename// 指定文件保存路徑destination := "./uploads/" + filename// 創建 uploads 目錄(如果不存在)err = os.MkdirAll("./uploads", os.ModePerm)if err != nil {c.String(http.StatusInternalServerError, fmt.Sprintf("mkdir err: %s", err.Error()))return}// 保存上傳的文件到指定位置if err := c.SaveUploadedFile(file, destination); err != nil {c.String(http.StatusInternalServerError, fmt.Sprintf("upload file err: %s", err.Error()))return}// 返回成功信息c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", filename))})
當然對于接受到的前端數據c,也可以進行后端變量的數據綁定:
方法 | 說明 |
---|---|
c.ShouldBindJSON(&obj) | 將請求體 JSON 綁定到結構體,自動觸發?binding ?標簽驗證 |
c.ShouldBindQuery(&obj) | 綁定 URL 查詢參數到結構體 |
c.ShouldBindUri(&obj) | 綁定路由參數到結構體 |
c.Bind(&obj) | 自動根據?Content-Type ?選擇綁定方式,驗證失敗直接返回 400 錯誤 |
以下為一段示例代碼:
type User struct {Name string `json:"name" binding:"required"`// 必填且必須是郵箱格式Email string `json:"email" binding:"required,email"`// 數值范圍限制(18 ≤ Age ≤ 60)Age int `json:"age" binding:"gte=18,lte=60"`// 字符串長度限制(6 ≤ 密碼長度 ≤ 16)Password string `json:"password" binding:"required,min=6,max=16"`// 枚舉值(只能是 "male" 或 "female")Gender string `json:"gender" binding:"oneof=male female"`
}
func CreateUser(c *gin.Context) {var user Userif err := c.ShouldBindJSON(&user); err != nil {// 返回驗證錯誤信息c.JSON(400, gin.H{"error": err.Error()})return}// 驗證通過后的業務邏輯c.JSON(200, gin.H{"message": "User created"})
}
? ? ? ? ?上述代碼,會將前端傳回的json數據c的值綁定在結構體變量user中,并驗證數據是否符合結構體當中的binding要求,若不滿足則會產生對應的錯誤err,否則err為空。
? ? ? ? 對于中間件與流程控制,有如下方法:?
方法 | 說明 |
---|---|
c.Next() | 繼續執行后續中間件或處理函數(通常在中間件中調用) |
c.Abort() | 終止當前請求的后續處理(如權限校驗失敗時) |
c.AbortWithStatus(code) | 終止并返回指定 HTTP 狀態碼 |
c.Set("key", value) | 存儲數據供后續中間件或處理函數使用 |
c.Get("key") | 獲取通過?Set ?存儲的值 |
中間件示例代碼:
func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {token := c.GetHeader("Authorization")if token != "valid-token" {c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})return}c.Set("user", "admin") // 傳遞用戶信息c.Next()}
}// 路由中使用中間件
router.GET("/admin", AuthMiddleware(), func(c *gin.Context) {user := c.MustGet("user").(string)c.String(200, "Welcome %s", user)
})
? ? ? ? 關于響應的請求頭,以及Cookie,Session會話機制的內容,將在后續章節進一步詳細解釋。?
6.Gin框架實戰案例 -表單信息提交處理🌷
? ? ? ? 本次案例地前端是使用VUE3與Vite共同創建,采用的UI組件為ElementPlus-Form,如果你熟悉VUE2或其他UI組件庫,當然也可以使用。這里就不過多敘述前端的搭建了,前端頁面最終效果如下:
4.1 前端JS請求?🔅
? ? ? ? 對Create按鍵添加綁定函數,使得用戶點擊該按鈕的時候,能夠自動提交表單填寫的信息。
? ? ? ? ? ? ? ? ? ? ? ? ?
????????接著使用Axios,將前端的表單數據發送到后端,當然熟悉fetch的uu,也可以使用fetch的方法進行數據傳遞。? ? ? ? ? ? ?
4.2?后端Gin編寫?🔅?
? ? ? ? 首先先介紹一個概念-跨域請求(CORS):CORS(Cross-Origin Resource Sharing)是一種機制,允許服務器通過設置HTTP頭部來指定哪些源(域、協議或端口)可以訪問其資源。它用于解決瀏覽器的同源策略限制,使得不同源之間的資源可以安全地進行交互。?
? ? ? ? 為了使得數據可以從前端傳遞到后端,首先我們得先配置一下Gin的CORS,具體代碼如下:
r := gin.Default()// 自定義 CORS 中間件r.Use(func(c *gin.Context) {// 設置允許的請求頭c.Writer.Header().Set("Access-Control-Allow-Origin", "*")c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")if c.Request.Method == "OPTIONS" {c.AbortWithStatus(http.StatusNoContent)return}c.Next()})
? ? ? ? 配置完CORS之后,開始編寫處理函數部分:
r.POST("/submit-form", func(c *gin.Context) {var formData map[string]interface{}if err := c.BindJSON(&formData); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}c.JSON(http.StatusOK, gin.H{"message": "Form submitted successfully", "data": formData})})
? ? ? ? 這里與前端的請求相照應,由于前端發起的是POST方式,所以此處也使用r.POST,而不能使用r.GET,路徑對應前端的請求路徑,為?/submit-form 。
? ? ? ? 接著聲明一個?map[string]interface{}?類型的變量formData,用于存儲從請求體中解析出來的JSON數據。map[string]interface{}是一個通用的鍵值對結構,可以存儲任意類型的值。(關于Go語言當中map數據類型的內容,我確實沒寫過...后續有時間在補上。)
????????
c.BindJSON(&formData)
嘗試從請求體中解析JSON數據,并將其綁定到formData
變量中。如果解析失敗,err
會包含錯誤信息。如果解析失敗,使用c.JSON
發送一個400狀態碼(http.StatusBadRequest
)和一個包含錯誤信息的JSON響應。如果JSON解析成功,使用c.JSON
發送一個200狀態碼(http.StatusOK
)和一個包含成功消息和解析數據的JSON響應。
? ? ? ? 最后依據前端的訪問端口,進行對應的配置:
r.Run(":8000")
?至此,后端部分完成,下面開始測試:
1.使用npm run開啟前端界面,以及運行對應的后端Go文件。
2.在前端界面的表單中輸入信息,并點擊Create按鈕進行表單數據的提交
3.在后端Gin文件中,可以查看到剛剛的前端請求信息
?4.在前端界面中,使用F12,點擊Console,可以在控制臺看到,Gin所傳回來的后端數據,接著前端接受,使用變量接收數據,便可以將數據渲染顯示在網頁界面上了。