Rumah >pembangunan bahagian belakang >Golang >Pengepala versi berasaskan golang

Pengepala versi berasaskan golang

WBOY
WBOYke hadapan
2024-02-10 19:03:08469semak imbas

golang 上基于标头的版本控制

Kawalan versi berasaskan pengepala pada Golang ialah cara yang cekap untuk mengurus versi kod semasa pembangunan. Dengan menambahkan maklumat versi pada permulaan fail kod, pembangun boleh menjejaki perubahan kod dan sejarah versi dengan mudah. Kaedah kawalan versi ini bukan sahaja mudah digunakan, tetapi juga sesuai untuk projek semua saiz. Editor PHP Xigua akan memperkenalkan secara terperinci penggunaan dan langkah berjaga-jaga bagi kawalan versi berasaskan pengepala pada Golang dalam artikel ini untuk membantu pembangun mengurus dan mengekalkan kod dengan lebih baik. Sama ada anda seorang pemula atau pembangun berpengalaman, artikel ini akan memberi anda rujukan dan panduan yang berharga. Mari kita terokai teknologi kawalan versi yang menarik dan praktikal ini bersama-sama!

Kandungan soalan

Saya mahu menggunakan gin untuk melaksanakan kawalan versi berasaskan pengepala semasa dalam perjalanan. Saya sedang berfikir untuk menggunakan fungsi middleware untuk melakukan ini pada penghala.

Pelanggan akan memanggil url api yang sama dan versi akan berada dalam pengepala http tersuai seperti ini:

Panggil versi 1 Dapatkan /users/12345678 Versi yang diterima: v1

Panggil versi 2: Dapatkan /users/12345678 Versi yang diterima: v2

Jadi penghala boleh mengecam pengepala dan memanggil versi tertentu. Perkara seperti ini:

router := gin.Default()

            v1 := router.Group("/v1")
            v1.Use(VersionMiddleware())
            v1.GET("/user/:id", func(c *gin.Context) {
                c.String(http.StatusOK, "This is the v1 API")
            })

            v2 := router.Group("/v2")
            v2.Use(VersionMiddleware())
            v2.GET("/user/:id", func(c *gin.Context) {
                c.String(http.StatusOK, "This is the v2 API")
            })

func VersionMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        version := c.Request.Header.Get(configuration.GetConfigValue("VersionHeader"))

        // Construct the new URL path based on the version number
        path := fmt.Sprintf("/%s%s", version, c.Request.URL.Path)

        // Modify the request URL path to point to the new version-specific endpoint
        c.Request.URL.Path = path
        c.Next()
    }
}

Penyelesaian

Sila semak coretan kod di bawah. Saya menggunakan reverseproxy untuk mengubah hala ke versi yang diberikan. Anda perlu mengesahkan versi yang diberikan dengan teliti. Jika tidak, ia akan mengakibatkan panggilan rekursif.

Nota: Saya menggunakan dua versi /user /user get/v1/user/v2/userget

(

dan

).

Contoh kod

package main

import (
 "net/http"
 "net/http/httputil"
 "regexp"

 "github.com/gin-gonic/gin"
)



func main() {
 router := gin.default()
 router.use(versionmiddleware())


 v1 := router.group("/v1")
 v1.get("/user", func(c *gin.context) {
  c.string(http.statusok, "this is the v1 api")
 })

 v2 := router.group("/v2")
 v2.get("/user", func(c *gin.context) {
  c.string(http.statusok, "this is the v2 api")
 })

 router.run(":8082")
}



func versionmiddleware() gin.handlerfunc {
    return func(c *gin.context) {
  
  // you need to check c.request.url.path whether 
  // already have a version or not, if it has a valid
  // version, return.
  regex, _ := regexp.compile("/v[0-9]+")
  ver := regex.matchstring(c.request.url.path)
  if ver {
   return
  }

  version := c.request.header.get("accept-version")
  
  // you need to validate  given version by the user here.
  // if version is not a valid version, return error 
  // mentioning that given version is invalid.

  director := func(req *http.request) {
    r := c.request
    req.url.scheme = "http"
    req.url.host = r.host
    req.url.path =  "/"+ version + r.url.path
    }
  proxy := &httputil.reverseproxy{director: director}
  proxy.servehttp(c.writer, c.request)
 }
}

atau
  • Anda boleh melakukan ini menggunakan pembungkusan gin di bawah.
    Contoh
  • package main
    
    import (
     "net/http"
    
     "github.com/gin-gonic/gin"
     "github.com/udayangaac/stackoverflow/golang/75860989/ginwrapper"
    )
    
    
    
    func main() {
      engine := gin.default()
     router := ginwrapper.newrouter(engine)
    
     defaultrouter := router.default()
     defaultrouter.get("/profile",func(ctx *gin.context) {
    
     })
    
     v1 := router.withversion("/v1")
     v1.get("/user",func(ctx *gin.context) {
      ctx.string(http.statusok, "this is the profile v1 api")
     })
    
     v2 := router.withversion("/v2")
     v2.get("/user",func(ctx *gin.context) {
      ctx.string(http.statusok, "this is the profile v2 api")
     })
    
     
     engine.run(":8082")
    }
    

Pembungkusan

    package ginwrapper
    
    import (
     "fmt"
     "net/http"
    
     "github.com/gin-gonic/gin"
    )
    
    type router struct {
     router *gin.engine
     versiongroups map[string]*gin.routergroup
    }
    
    type versionedrouter struct {
     version string
     router
    }
    
    func newrouter(router *gin.engine) *router {
     return &router{
      router: router,
      versiongroups: make(map[string]*gin.routergroup),
     }
    }
    
    func (a *router) default() versionedrouter {
     return versionedrouter{router: *a }
    }
    
    func  (a *router) withversion(version string) versionedrouter {
     if _,ok := a.versiongroups[version]; ok {
      panic("cannot initialize same version multiple times")
     }
     a.versiongroups[version] = a.router.group(version)
     return versionedrouter{router: *a,version:version }
    }
    
    
    
    
    func (vr versionedrouter) get(relativepath string, handlers ...gin.handlerfunc)  {
     vr.handle(http.methodget,relativepath,handlers...)
    }
    
    // note: you need to follow the same for other http methods.
    // as an example, we can write a method for post http method as below,
    // 
    //  func (vr versionedrouter) post(relativepath string, handlers ...gin.handlerfunc)  {
    //   vr.handle(http.methodpost,relativepath,handlers...)
    //  }
    
    
    
    
    
    func (vr versionedrouter)handle(method,relativepath string, handlers ...gin.handlerfunc)  {
     if !vr.isrouteexist(method,relativepath) {
      vr.router.handle(method,relativepath,func(ctx *gin.context) {
       version := ctx.request.header.get("accept-version")
       if len(version) == 0 {
        ctx.string(http.statusbadrequest,"accept-version header is empty")
       }
       ctx.request.url.path = fmt.sprintf("/%s%s", version, ctx.request.url.path)
       vr.router.handlecontext(ctx)
      })
     }
    
     versionedrelativepath := vr.version + relativepath
     if !vr.isrouteexist(method,versionedrelativepath) {
      vr.router.handle(method,versionedrelativepath,handlers... )
     }
    }
    
    
    func (a versionedrouter) isrouteexist(method,relativepath string) bool {
     for _,route := range a.router.routes() {
      if route.method == method && relativepath == route.path {
       return true
      } 
     }
     return false
    }
    
    
  • Permintaan Contoh/v1/user
  • /v2/user
    curl --location 'localhost:8082/user' \
    --header 'accept-version: v1'
🎜🎜 🎜
curl --location 'localhost:8082/user' \
--header 'Accept-version: v2'

Atas ialah kandungan terperinci Pengepala versi berasaskan golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam