" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語(yǔ)言開(kāi)發(fā)中有了net/http為什么還要有g(shù)in的原理及使用場(chǎng)景解析

 更新時(shí)間:2023年08月07日 08:42:22   作者:陳晨  
這篇文章主要為大家介紹了Go語(yǔ)言有了net/http標(biāo)準(zhǔn)庫(kù)為什么還要有g(shù)in第三方庫(kù)的原理及使用場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

1. 簡(jiǎn)介

在Go語(yǔ)言中,net/http 包提供了一個(gè)強(qiáng)大且靈活的標(biāo)準(zhǔn)HTTP庫(kù),可以用來(lái)構(gòu)建Web應(yīng)用程序和處理HTTP請(qǐng)求。這個(gè)包是Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)的一部分,因此所有的Go程序都可以直接使用它。既然已經(jīng)有 net/http 這樣強(qiáng)大和靈活的標(biāo)準(zhǔn)庫(kù),為什么還出現(xiàn)了像 Gin 這樣的,方便我們構(gòu)建Web應(yīng)用程序的第三方庫(kù)?

其實(shí)在于net/http的定位,其提供了基本的HTTP功能,但它的設(shè)計(jì)目標(biāo)是簡(jiǎn)單和通用性,而不是提供高級(jí)特性和便利的開(kāi)發(fā)體驗(yàn)。在處理HTTP請(qǐng)求和構(gòu)建Web應(yīng)用時(shí),可能會(huì)遇到一系列的問(wèn)題,這也造就了Gin 這樣的第三方庫(kù)的出現(xiàn)。

下文我們將對(duì)一系列場(chǎng)景的介紹,通過(guò)比對(duì) net/http 和 Gin 二者在這些場(chǎng)景下的不同實(shí)現(xiàn),進(jìn)而說(shuō)明Gin 框架存在的必要性。

2. 復(fù)雜路由場(chǎng)景處理

在實(shí)際的Web應(yīng)用程序開(kāi)發(fā)中,使用同一個(gè)路由前綴的場(chǎng)景非常普遍,這里舉兩個(gè)比較常見(jiàn)的例子。

比如在設(shè)計(jì)API時(shí),可能會(huì)隨著時(shí)間的推移對(duì)API進(jìn)行更新和改進(jìn)。為了保持向后兼容性,并允許多個(gè)API版本共存,通常會(huì)使用類(lèi)似 /v1、/v2 這樣的路由前綴來(lái)區(qū)分不同版本的API。

還有另外一個(gè)場(chǎng)景,一個(gè)大型Web應(yīng)用程序經(jīng)常是由多個(gè)模塊組成,每個(gè)模塊負(fù)責(zé)不同的功能。為了更好地組織代碼和區(qū)分不同模塊的路由,經(jīng)常都是使用模塊名作為路由前綴。

在這兩個(gè)場(chǎng)景中,大概率都會(huì)使用同一個(gè)路由前綴。如果使用net/http 來(lái)框架web應(yīng)用,實(shí)現(xiàn)大概如下:

package main
import (
        "fmt"
        "net/http"
)
func handleUsersV1(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "User list in v1")
}
func handlePostsV1(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Post list in v1")
}
func main() {
        http.HandleFunc("/v1/users", handleUsersV1)
        http.HandleFunc("/v1/posts", handlePostsV1)
        http.ListenAndServe(":8080", nil)
}

在上面的示例中,我們手動(dòng)使用 http.HandleFunc 來(lái)定義不同的路由處理函數(shù)。

代碼示例看起來(lái)沒(méi)有太大問(wèn)題,但是是因?yàn)橹挥袃蓚€(gè)路由組,如果隨著路由數(shù)量增加,處理函數(shù)的數(shù)量也會(huì)增加,代碼會(huì)變得越來(lái)越復(fù)雜和冗長(zhǎng)。而且每一個(gè)路由規(guī)則都需要手動(dòng)設(shè)置路由前綴,如例子中的 v1 前綴,如果前綴是 /v1/v2/... 這樣子設(shè)置起來(lái),會(huì)導(dǎo)致代碼架構(gòu)不清晰,同時(shí)操作繁雜,容易出錯(cuò)。

但是相比之下,Gin 框架實(shí)現(xiàn)了路由分組的功能,下面來(lái)看Gin 框架來(lái)對(duì)該功能的實(shí)現(xiàn):

package main
import (
        "fmt"
        "github.com/gin-gonic/gin"
)
func main() {
        router := gin.Default()
        // 創(chuàng)建一個(gè)路由組
        v1 := router.Group("/v1")
        {
                v1.GET("/users", func(c *gin.Context) {
                        c.String(200, "User list in v1")
                })
                v1.GET("/posts", func(c *gin.Context) {
                        c.String(200, "Post list in v1")
                })
        }
        router.Run(":8080")
}

在上面的例子中,通過(guò)router.Group 創(chuàng)建了一個(gè)v1 路由前綴的路由組,我們?cè)O(shè)置路由規(guī)則時(shí),不需要再設(shè)置路由前綴,框架會(huì)自動(dòng)幫我們組裝好。

同時(shí),相同路由前綴的規(guī)則,也在同一個(gè)代碼塊里進(jìn)行維護(hù)。 相比于 net/http 代碼庫(kù),Gin 使得代碼結(jié)構(gòu)更清晰、更易于管理。

3. 中間件處理

在web應(yīng)用請(qǐng)求處理過(guò)程中,除了執(zhí)行具體的業(yè)務(wù)邏輯之外,往往需要在這之前執(zhí)行一些通用的邏輯,比如鑒權(quán)操作,錯(cuò)誤處理或者是日志打印功能,這些邏輯我們統(tǒng)稱(chēng)為中間件處理邏輯,而且往往是必不可少的。

首先對(duì)于錯(cuò)誤處理,在應(yīng)用程序的執(zhí)行過(guò)程中,可能會(huì)發(fā)生一些內(nèi)部錯(cuò)誤,如數(shù)據(jù)庫(kù)連接失敗、文件讀取錯(cuò)誤等。合理的錯(cuò)誤處理可以避免這些錯(cuò)誤導(dǎo)致整個(gè)應(yīng)用崩潰,而是通過(guò)適當(dāng)?shù)腻e(cuò)誤響應(yīng)告知客戶(hù)端。

對(duì)于鑒權(quán)操作,在許多web處理場(chǎng)景中,經(jīng)常都是用戶(hù)認(rèn)證之后,才能訪(fǎng)問(wèn)某些受限資源或執(zhí)行某些操作。同時(shí)鑒權(quán)操作還可以限制用戶(hù)的權(quán)限,避免用戶(hù)有未經(jīng)授權(quán)的訪(fǎng)問(wèn),這有助于提高程序的安全性。

因此,一個(gè)完整的HTTP請(qǐng)求處理邏輯,是極有可能需要這些中間件處理邏輯的。而且理論上框架或者類(lèi)庫(kù)應(yīng)該有對(duì)中間件邏輯的支持。下面先來(lái)看看 net/http 能怎么去實(shí)現(xiàn):

package main
import (
        "fmt"
        "log"
        "net/http"
)
// 錯(cuò)誤處理中間件
func errorHandler(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                defer func() {
                        if err := recover(); err != nil {
                                http.Error(w, "Internal Server Error", http.StatusInternalServerError)
                                log.Printf("Panic: %v", err)
                        }
                }()
                next.ServeHTTP(w, r)
        })
}
// 認(rèn)證鑒權(quán)中間件
func authMiddleware(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                // 模擬身份驗(yàn)證
                if r.Header.Get("Authorization") != "secret" {
                        http.Error(w, "Unauthorized", http.StatusUnauthorized)
                        return
                }
                next.ServeHTTP(w, r)
        })
}
// 處理業(yè)務(wù)邏輯
func helloHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, World!")
}
// 另外
func anotherHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Another endpoint")
}
func main() {
        // 創(chuàng)建路由處理器
        router := http.NewServeMux()
        // 應(yīng)用中間件, 注冊(cè)處理器
        handler := errorHandler(authMiddleware(http.HandlerFunc(helloHandler)))
        router.Handle("/", handler)
        // 應(yīng)用中間件, 注冊(cè)另外一個(gè)請(qǐng)求的處理器
        another := errorHandler(authMiddleware(http.HandlerFunc(anotherHandler)))
        router.Handle("/another", another)
        // 啟動(dòng)服務(wù)器
        http.ListenAndServe(":8080", router)
}

在上述示例中,我們?cè)?code>net/http 中通過(guò)errorHandler 和 authMiddleware 兩個(gè)中間件實(shí)現(xiàn)了錯(cuò)誤處理和鑒權(quán)功能。 接下來(lái)我們查看示例代碼的第49行,可以發(fā)現(xiàn)代碼通過(guò)裝飾者模式,給原本的處理器增加了錯(cuò)誤處理和鑒權(quán)操作功能。

這段代碼的實(shí)現(xiàn)的優(yōu)點(diǎn),是通過(guò)裝飾者模式,對(duì)多個(gè)處理函數(shù)進(jìn)行組合,形成處理器鏈,實(shí)現(xiàn)了錯(cuò)誤處理和認(rèn)證鑒權(quán)功能。而不需要在每個(gè)處理函數(shù)handler 中去加上這部分邏輯,這使得代碼具備更高的可讀性和可維護(hù)性。

但是這里也存在著一個(gè)很明顯的缺點(diǎn),這個(gè)功能并不是框架給我們提供的,而是我們自己實(shí)現(xiàn)的。我們每新增一個(gè)處理函數(shù)handler, 都需要對(duì)這個(gè)handler 進(jìn)行裝飾,為其增加錯(cuò)誤處理和鑒權(quán)操作,這在增加我們負(fù)擔(dān)的同時(shí),也容易出錯(cuò)。同時(shí)需求也是不斷變化的,有可能部分請(qǐng)求只需要錯(cuò)誤處理了,一部分請(qǐng)求只需要鑒權(quán)操作,一部分請(qǐng)求既需要錯(cuò)誤處理也需要鑒權(quán)操作,基于這個(gè)代碼結(jié)構(gòu),其會(huì)變得越來(lái)越難維護(hù)。

相比之下,Gin 框架提供了一種更靈活的方式來(lái)啟用和禁用中間件邏輯,能針對(duì)某個(gè)路由組進(jìn)行設(shè)置,而不需要對(duì)每個(gè)路由規(guī)則單獨(dú)設(shè)置,下面展示下示例代碼:

package main
import (
        "github.com/gin-gonic/gin"
)
func authMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
                // 模擬身份驗(yàn)證
                if c.GetHeader("Authorization") != "secret" {
                        c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
                        return
                }
                c.Next()
        }
}
func main() {
        router := gin.Default()
        // 全局添加 Logger 和 Recovery 中間件
        // 創(chuàng)建一個(gè)路由組,該組中的所有路由都會(huì)應(yīng)用 authMiddleware 中間件
        authenticated := router.Group("/")
        authenticated.Use(authMiddleware())
        {
                authenticated.GET("/hello", func(c *gin.Context) {
                        c.String(200, "Hello, World!")
                })
                authenticated.GET("/private", func(c *gin.Context) {
                        c.String(200, "Private data")
                })
        }
        // 不在路由組中,因此沒(méi)有應(yīng)用 authMiddleware 中間件
        router.GET("/welcome", func(c *gin.Context) {
                c.String(200, "Welcome!")
        })
        router.Run(":8080")
}

在上述示例中,我們通過(guò)router.Group("/") 創(chuàng)建了一個(gè)名為 authenticated 的路由組,然后使用 Use 方法,給該路由組啟用 authMiddleware 中間件。在這路由組下所有的路由規(guī)則,都會(huì)自動(dòng)執(zhí)行authMiddleware 實(shí)現(xiàn)的鑒權(quán)操作。

相對(duì)于net/http 的優(yōu)點(diǎn),首先是不需要對(duì)每個(gè)handler 進(jìn)行裝飾,增加中間件邏輯,用戶(hù)只需要專(zhuān)注于業(yè)務(wù)邏輯的開(kāi)發(fā)即可,減輕了負(fù)擔(dān)。

其次可維護(hù)性更高了,如果業(yè)務(wù)需要不再需要進(jìn)行鑒權(quán)操作,gin 只需要?jiǎng)h除掉Use 方法的調(diào)用,而net/http 則需要對(duì)所有handler的裝飾操作進(jìn)行處理,刪除掉裝飾者節(jié)點(diǎn)中的鑒權(quán)操作節(jié)點(diǎn),工作量相對(duì)于gin 來(lái)說(shuō)非常大,同時(shí)也容易出錯(cuò)。

最后,gin 在處理不同部分的請(qǐng)求需要使用不同中間件的場(chǎng)景下,更為靈活,實(shí)現(xiàn)起來(lái)也更為簡(jiǎn)單。比如 一部分請(qǐng)求需要鑒權(quán)操作,一部分請(qǐng)求需要錯(cuò)誤里處理,還有一部分既需要錯(cuò)誤處理,也需要鑒權(quán)操作。這種場(chǎng)景下,只需要通過(guò)gin 創(chuàng)建三個(gè)路由組router, 然后不同的路由組分別調(diào)用 Use 方法啟用不同的中間件,即可實(shí)現(xiàn)需求了,這相對(duì)于net/http 更為靈活和可維護(hù)。

這也是為什么有net/http 的前提下,還出現(xiàn)了gin 框架的重要原因之一。

4. 數(shù)據(jù)綁定

在處理HTTP請(qǐng)求時(shí),比較常見(jiàn)的功能,是將請(qǐng)求中的數(shù)據(jù)自動(dòng)綁定到結(jié)構(gòu)體當(dāng)中。下面以一個(gè)表單數(shù)據(jù)為例,如果使用net/http,如何將數(shù)據(jù)綁定到結(jié)構(gòu)體當(dāng)中:

package main
import (
        "fmt"
        "log"
        "net/http"
)
type User struct {
        Name  string `json:"name"`
        Email string `json:"email"`
}
func handleFormSubmit(w http.ResponseWriter, r *http.Request) {
        var user User
        // 將表單數(shù)據(jù)綁定到 User 結(jié)構(gòu)體
        user.Name = r.FormValue("name")
        user.Email = r.FormValue("email")
        // 處理用戶(hù)數(shù)據(jù)
        fmt.Fprintf(w, "用戶(hù)已創(chuàng)建:%s (%s)", user.Name, user.Email)
}
func main() {
        http.HandleFunc("/createUser", handleFormSubmit)
        http.ListenAndServe(":8080", nil)
}

我們需要調(diào)用FormValue 方法,一個(gè)一個(gè)得從表單中讀取出數(shù)據(jù),然后設(shè)置到結(jié)構(gòu)體當(dāng)中。而且在字段比較多的情況下,我們很有可能漏掉其中的某些字段,導(dǎo)致后續(xù)處理邏輯出現(xiàn)問(wèn)題。而且每個(gè)字段都需要我們手動(dòng)讀取設(shè)置,也很影響我們的開(kāi)發(fā)效率。

下面我們來(lái)看看Gin 是如何讀取表單數(shù)據(jù),將其設(shè)置到結(jié)構(gòu)體當(dāng)中的:

package main
import (
        "fmt"
        "github.com/gin-gonic/gin"
)
type User struct {
        Name  string `json:"name"`
        Email string `json:"email"`
}
func handleFormSubmit(c *gin.Context) {
        var user User
        // 將表單數(shù)據(jù)綁定到 User 結(jié)構(gòu)體
        err := c.ShouldBind(&user)
        if err != nil {
                c.JSON(http.StatusBadRequest, gin.H{"error": "無(wú)效的表單數(shù)據(jù)"})
                return
        }
        // 處理用戶(hù)數(shù)據(jù)
        c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("用戶(hù)已創(chuàng)建:%s (%s)", user.Name, user.Email)})
}
func main() {
        router := gin.Default()
        router.POST("/createUser", handleFormSubmit)
        router.Run(":8080")
}

看上面示例代碼的第17行,可以看到直接調(diào)用ShouldBind 函數(shù),便可以自動(dòng)將表單的數(shù)據(jù)自動(dòng)映射到結(jié)構(gòu)體當(dāng)中,不再需要一個(gè)一個(gè)字段讀取,然后再單獨(dú)設(shè)置到結(jié)構(gòu)體當(dāng)中。

相比于使用net/httpgin 框架在數(shù)據(jù)綁定方面更為方便,同時(shí)也不容易出錯(cuò)。gin 提供了各種 api , 能夠?qū)⒏鞣N類(lèi)型的數(shù)據(jù)映射到結(jié)構(gòu)體當(dāng)中,用戶(hù)只需要調(diào)用對(duì)應(yīng)的 api 即可。而net/http 則未提供相對(duì)應(yīng)的操作,需要用戶(hù)讀取數(shù)據(jù),然后手動(dòng)設(shè)置到結(jié)構(gòu)體當(dāng)中。

5. 總結(jié)

在Go語(yǔ)言中, net/http 提供了基本的HTTP功能,但它的設(shè)計(jì)目標(biāo)是簡(jiǎn)單和通用性,而不是提供高級(jí)特性和便利的開(kāi)發(fā)體驗(yàn)。在處理HTTP請(qǐng)求和構(gòu)建Web應(yīng)用時(shí),處理復(fù)雜的路由規(guī)則時(shí),會(huì)顯得力不從心;同時(shí)對(duì)于一些公共操作,比如日志記錄,錯(cuò)誤處理等,很難做到可插拔設(shè)計(jì);想要將請(qǐng)求數(shù)據(jù)綁定到結(jié)構(gòu)體中,net/http 也沒(méi)有提供一些簡(jiǎn)易的操作,都是需要用戶(hù)手動(dòng)去實(shí)現(xiàn)的。

這就是為什么出現(xiàn)了像 Gin這樣的第三方庫(kù),其是一個(gè)構(gòu)建在 net/http 之上,旨在簡(jiǎn)化和加速Web應(yīng)用程序的開(kāi)發(fā)。

總的來(lái)說(shuō),Gin 可以幫助開(kāi)發(fā)者更高效地構(gòu)建Web應(yīng)用程序,提供了更好的開(kāi)發(fā)體驗(yàn)和更豐富的功能。當(dāng)然,選擇使用 net/http 還是 Gin 取決于項(xiàng)目的規(guī)模、需求和個(gè)人喜好。對(duì)于簡(jiǎn)單的小型項(xiàng)目,net/http 可能已經(jīng)足夠,但對(duì)于復(fù)雜的應(yīng)用程序,Gin 可能會(huì)更適合。

以上就是有了net/http, 為什么還要有g(shù)in的詳細(xì)內(nèi)容,更多關(guān)于有了net/http, 為什么還要有g(shù)in的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go mod tidy加載模塊超時(shí)的問(wèn)題及解決

    go mod tidy加載模塊超時(shí)的問(wèn)題及解決

    go mod tidy加載模塊超時(shí)的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Go語(yǔ)言導(dǎo)出內(nèi)容到Excel的方法

    Go語(yǔ)言導(dǎo)出內(nèi)容到Excel的方法

    這篇文章主要介紹了Go語(yǔ)言導(dǎo)出內(nèi)容到Excel的方法,涉及Go語(yǔ)言操作excel的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • golang通用的grpc?http基礎(chǔ)開(kāi)發(fā)框架使用快速入門(mén)

    golang通用的grpc?http基礎(chǔ)開(kāi)發(fā)框架使用快速入門(mén)

    這篇文章主要為大家介紹了golang通用的grpc?http基礎(chǔ)開(kāi)發(fā)框架使用快速入門(mén)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Go語(yǔ)言之io.ReadAtLeast函數(shù)的基本使用和原理解析

    Go語(yǔ)言之io.ReadAtLeast函數(shù)的基本使用和原理解析

    io.ReadAtLeast函數(shù)是Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供的一個(gè)工具函數(shù),能夠從數(shù)據(jù)源讀取至少指定數(shù)量的字節(jié)數(shù)據(jù)到緩沖區(qū)中,這篇文章主要介紹了io.ReadAtLeast函數(shù)的相關(guān)知識(shí),需要的朋友可以參考下
    2023-07-07
  • gin 獲取post請(qǐng)求的json body操作

    gin 獲取post請(qǐng)求的json body操作

    這篇文章主要介紹了gin 獲取post請(qǐng)求的json body操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-03-03
  • go的切片擴(kuò)容機(jī)制詳解

    go的切片擴(kuò)容機(jī)制詳解

    本文主要介紹了go的切片擴(kuò)容機(jī)制詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • HTTP服務(wù)壓力測(cè)試工具及相關(guān)術(shù)語(yǔ)講解

    HTTP服務(wù)壓力測(cè)試工具及相關(guān)術(shù)語(yǔ)講解

    這篇文章主要為大家介紹了HTTP服務(wù)壓力測(cè)試工具使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • go高并發(fā)時(shí)append方法偶現(xiàn)錯(cuò)誤解決分析

    go高并發(fā)時(shí)append方法偶現(xiàn)錯(cuò)誤解決分析

    這篇文章主要為大家介紹了go高并發(fā)時(shí)append方法偶現(xiàn)錯(cuò)誤解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Go語(yǔ)言defer語(yǔ)句的三種機(jī)制整理

    Go語(yǔ)言defer語(yǔ)句的三種機(jī)制整理

    在本篇文章里小編給大家分享的是一篇關(guān)于Go語(yǔ)言defer語(yǔ)句的三種機(jī)制整理,需要的朋友們學(xué)習(xí)下吧。
    2020-03-03
  • Go語(yǔ)言map實(shí)現(xiàn)順序讀取

    Go語(yǔ)言map實(shí)現(xiàn)順序讀取

    當(dāng)我們遍歷 map 時(shí),那就是輸出的鍵值對(duì)順序是不確定的,本文主要介紹了Go語(yǔ)言map實(shí)現(xiàn)順序讀取, 文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05

最新評(píng)論