日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Go语言实战 : API服务器 (8) 中间件

發(fā)布時(shí)間:2023/11/29 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go语言实战 : API服务器 (8) 中间件 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

為什么需要中間件

我們可能需要對(duì)每個(gè)請(qǐng)求/返回做一些特定的操作,比如

  • 記錄請(qǐng)求的 log 信息
  • 在返回中插入一個(gè) Header
  • 部分接口進(jìn)行鑒權(quán)
    這些都需要一個(gè)統(tǒng)一的入口。這個(gè)功能可以通過(guò)引入 middleware 中間件來(lái)解決。Go 的 net/http 設(shè)計(jì)的一大特點(diǎn)是特別容易構(gòu)建中間件。apiserver 所使用的 gin 框架也提供了類似的中間件。

gin里面的中間件

在 gin 中可以設(shè)置 3 種類型的 middleware:

  • 全局中間件
router := gin.New() // 添加自定義的 logger 中間件 router.Use(middleware.Logger(), gin.Recovery())
  • 單個(gè)路由中間件
userRouter.GET("/profile/", middleware.Auth(), handler.UserProfile) userRouter.POST("/update", middleware.Auth(), handler.UpdateUserProfile)
  • 群組中間件
authorized := router.Group("/", MyMiddelware()) // 或者這樣用: authorized := router.Group("/") authorized.Use(MyMiddelware()) {authorized.POST("/login", loginEndpoint) }

在請(qǐng)求和返回的 Header 中插入 X-Request-Id

X-Request-Id 值為 32 位的 UUID,用于唯一標(biāo)識(shí)一次 HTTP 請(qǐng)求

func RequestId() gin.HandlerFunc{return func(c *gin.Context) {requestId := c.Request.Header.Get("X-Request-Id")if requestId==""{v4:= uuid.NewV4()requestId=v4.String()}c.Set("X-Request-Id", requestId)c.Writer.Header().Set("X-Request-Id", requestId)c.Next()}

日志中間件

  • 獲取請(qǐng)求路徑,并且進(jìn)行匹配(只對(duì)業(yè)務(wù)邏輯進(jìn)行日志記錄)
  • path := c.Request.URL.Pathreg:= regexp.MustCompile("(/v1/user|/login)")if !reg.MatchString(path) {return}// Skip for the health check requests.if path == "/sd/health" || path == "/sd/ram" || path == "/sd/cpu" || path == "/sd/disk" {return}
  • 獲取請(qǐng)求中的IP等信息,并且給請(qǐng)求重新賦值(請(qǐng)求讀取完會(huì)被置空)
  • var bodys []byteif c.Request.Body!=nil{bodys, _ = ioutil.ReadAll(c.Request.Body)}c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodys))method := c.Request.Methodip := c.ClientIP()
  • 將響應(yīng)重定向到指定IO流,并且提取里面的信息
  • blw := &bodyLogWriter{body: bytes.NewBufferString(""),ResponseWriter: c.Writer,}c.Writer=blwc.Next()var response handler.Responseif err := json.Unmarshal(blw.body.Bytes(), &response); err != nil {log.Println(err, "response body can not unmarshal to model.Response struct, body: %s", string(blw.body.Bytes()))code = errno.InternalServerError.Codemessage = err.Error()} else {code = response.Codemessage = response.Message}} func (w bodyLogWriter) Write(b []byte) (int, error) {w.body.Write(b)return w.ResponseWriter.Write(b)
  • 將從請(qǐng)求與響應(yīng)中提取的信息進(jìn)行輸出
  • log.Printf("%-13s | %-12s | %s %s | {code: %d, message: %s}", sub, ip, pad.Right(method, 5, ""), path, code, message)

    測(cè)試

    X-Request-id

    可以看到,HTTP 返回的 Header 有 32 位的 UUID:

    日志

    每個(gè)請(qǐng)求的日志信息分為4個(gè)部分

    • 耗時(shí)
    • 請(qǐng)求 IP
    • HTTP 方法 HTTP 路徑
    • 返回的 Code 和 Message

    總結(jié)

    以上是生活随笔為你收集整理的Go语言实战 : API服务器 (8) 中间件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。