Heim  >  Artikel  >  Backend-Entwicklung  >  Headerbasierte Versionierung auf Golang

Headerbasierte Versionierung auf Golang

WBOY
WBOYnach vorne
2024-02-10 19:03:08430Durchsuche

golang 上基于标头的版本控制

Header-basierte Versionskontrolle auf Golang ist eine effiziente Möglichkeit, Codeversionen während der Entwicklung zu verwalten. Durch das Hinzufügen von Versionsinformationen am Anfang von Codedateien können Entwickler Codeänderungen und Versionsverlauf einfach verfolgen. Diese Versionskontrollmethode ist nicht nur einfach zu verwenden, sondern auch für Projekte jeder Größe geeignet. Der PHP-Editor Xigua wird in diesem Artikel ausführlich die Verwendung und Vorsichtsmaßnahmen der Header-basierten Versionskontrolle auf Golang vorstellen, um Entwicklern dabei zu helfen, Code besser zu verwalten und zu warten. Egal, ob Sie Anfänger oder erfahrener Entwickler sind, dieser Artikel bietet Ihnen wertvolle Referenzen und Anleitungen. Lassen Sie uns gemeinsam diese interessante und praktische Versionskontrolltechnologie erkunden!

Frageninhalt

Ich möchte Gin verwenden, um unterwegs eine Header-basierte Versionskontrolle zu implementieren. Ich denke darüber nach, eine Middleware-Funktion zu verwenden, um dies auf dem Router zu tun.

Der Client ruft dieselbe API-URL auf und die Version befindet sich in einem benutzerdefinierten HTTP-Header wie diesem:

Version 1 aufrufen Holen Sie sich /users/12345678 Akzeptierte Version: v1

Version 2 aufrufen: Holen Sie sich /users/12345678 Akzeptierte Version: v2

So kann der Router den Header erkennen und die spezifische Version aufrufen. Dinge wie diese:

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()
    }
}

Workaround

Bitte überprüfen Sie den Codeausschnitt unten. Ich verwende reverseproxy, um zu einer bestimmten Version umzuleiten. Sie müssen eine bestimmte Version sorgfältig überprüfen. Andernfalls kommt es zu rekursiven Aufrufen.

Hinweis: Ich habe zwei Versionen von /user /user get/v1/user/v2/userget

verwendet (

und

).

Beispielcode

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)
 }
}

oder
  • Sie können dies mit der untenstehenden Gin-Verpackung tun.
    Beispiel
  • 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")
    }
    

Verpackung

    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
    }
    
    
  • Musteranfrage/v1/user
  • /v2/user
    curl --location 'localhost:8082/user' \
    --header 'accept-version: v1'
🎜🎜 🎜
curl --location 'localhost:8082/user' \
--header 'Accept-version: v2'

Das obige ist der detaillierte Inhalt vonHeaderbasierte Versionierung auf Golang. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen