Golang中如何验证HTTP URL中的UUID

Golang中如何验证HTTP URL中的UUID 你好,

我正在使用Go开发一个REST API,需要一种方法来验证URL参数是否符合UUID格式。

router := httprouter.New()
router.GET("/", Index)
router.GET("/books/{uuid}", BookIndex)

对于整数ID,我使用正则表达式 [0-9]+ 来验证,如下所示:

router.GET("/books/{uuid:[0-9]+}", BookIndex)

遗憾的是,我找不到用于UUID的正则表达式。因此,我想请教一下,您是否有关于如何在HTTP URL中验证UUID格式的想法。

谢谢


更多关于Golang中如何验证HTTP URL中的UUID的实战教程也可以访问 https://www.itying.com/category-94-b0.html

11 回复

感谢分享,我在这里找到了很多有趣的信息。一篇真正的好文章。

更多关于Golang中如何验证HTTP URL中的UUID的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


因为当UUID仅作为字符串传递而未经验证时,某些路由之间会产生混淆。

@luk4z7

非常感谢。您的解决方案对我有效。

服务器不应接受URL参数不符合UUID格式的请求

是否有特定原因导致服务器不应接受请求?(然后在处理程序中验证URI)

你好 @geosoft1

感谢你的回答。

我已经看过这个帖子了,但这不是我想要的。如果URL参数不符合UUID格式,服务器就不应该接受这个请求。如果我采用这个帖子中提出的解决方案,我将不得不处理这个请求并返回一个错误状态,而这并不是我想要实现的行为。

再次感谢

好的,服务器总是会接收请求,无论你是否使用正则表达式来匹配路由。但那个讨论的核心思想是避免在路由中使用正则表达式,因为它的开销较大。不过,如果你不想在处理器中检查UUID,可以在中间件中进行检查。

r.HandleFunc("/{id:[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}}/import", YourHandler)

已修复,尝试创建一个中间件,你可以用同样的方式返回一个带有状态码的响应。

@luk4z7 你好, 我有个问题想请教。你的解决方案对我有效,但仅当UUID位于URL末尾时才有效。例如,对于下面的URL它就不起作用:

r.HandleFunc("/{id:[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/import}", YourHandler)

你知道原因或者有办法解决这个问题吗?

谢谢

package main

import (
	"github.com/gorilla/mux"
	"log"
	"net/http"
)

func YourHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Gorilla!\n"))
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/{id:[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$}", YourHandler)

	log.Fatal(http.ListenAndServe(":8000", r))
}

如何在Go中验证UUID v4?

package main

import (
    "fmt"
    "regexp"
)

var uuidV4Pattern = regexp.MustCompile(`^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$`)

func IsValidUUIDV4(uuid string) bool {
    return uuidV4Pattern.MatchString(uuid)
}

func main() {
    fmt.Println(IsValidUUIDV4("123e4567-e89b-12d3-a456-426614174000")) // true
    fmt.Println(IsValidUUIDV4("123e4567-e89b-12d3-a456-4266141740zz")) // false
}

在Go中验证URL中的UUID参数,可以使用httprouter的正则表达式功能配合Go标准库的regexp包。以下是完整的解决方案:

1. 定义UUID正则表达式

UUID的正则表达式可以这样定义:

package main

import (
    "regexp"
)

// UUID正则表达式(支持带或不带连字符)
const uuidPattern = `[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}`

// 严格版本的UUID正则表达式(必须带连字符)
const strictUUIDPattern = `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`

2. 在httprouter中使用正则表达式验证

package main

import (
    "fmt"
    "log"
    "net/http"
    "github.com/julienschmidt/httprouter"
)

func main() {
    router := httprouter.New()
    
    // 使用正则表达式验证UUID参数
    router.GET("/books/:uuid", BookIndex)
    router.GET("/books/strict/:uuid", BookIndexStrict)
    
    log.Fatal(http.ListenAndServe(":8080", router))
}

// 处理带连字符的UUID
func BookIndex(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    uuid := ps.ByName("uuid")
    
    // 验证UUID格式
    matched, _ := regexp.MatchString(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`, uuid)
    
    if !matched {
        http.Error(w, "Invalid UUID format", http.StatusBadRequest)
        return
    }
    
    fmt.Fprintf(w, "Valid UUID: %s", uuid)
}

// 处理严格验证的UUID(路由级别验证)
func BookIndexStrict(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    uuid := ps.ByName("uuid")
    fmt.Fprintf(w, "Strict UUID: %s", uuid)
}

3. 使用预编译的正则表达式提高性能

package main

import (
    "fmt"
    "log"
    "net/http"
    "regexp"
    "github.com/julienschmidt/httprouter"
)

var (
    uuidRegex = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)
)

func main() {
    router := httprouter.New()
    
    // 在路由定义中使用正则表达式
    router.GET("/books/:uuid", validateUUID(BookIndex))
    
    log.Fatal(http.ListenAndServe(":8080", router))
}

// 中间件验证UUID
func validateUUID(next httprouter.Handle) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        uuid := ps.ByName("uuid")
        
        if !uuidRegex.MatchString(uuid) {
            http.Error(w, "Invalid UUID format", http.StatusBadRequest)
            return
        }
        
        next(w, r, ps)
    }
}

func BookIndex(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    uuid := ps.ByName("uuid")
    fmt.Fprintf(w, "Processing book with UUID: %s", uuid)
}

4. 使用标准库的uuid包进行验证

package main

import (
    "fmt"
    "log"
    "net/http"
    "github.com/google/uuid"
    "github.com/julienschmidt/httprouter"
)

func main() {
    router := httprouter.New()
    
    router.GET("/books/:uuid", validateUUIDWithPackage(BookIndex))
    
    log.Fatal(http.ListenAndServe(":8080", router))
}

// 使用google/uuid包验证
func validateUUIDWithPackage(next httprouter.Handle) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        uuidStr := ps.ByName("uuid")
        
        _, err := uuid.Parse(uuidStr)
        if err != nil {
            http.Error(w, "Invalid UUID format", http.StatusBadRequest)
            return
        }
        
        next(w, r, ps)
    }
}

func BookIndex(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    uuidStr := ps.ByName("uuid")
    fmt.Fprintf(w, "Valid UUID using package: %s", uuidStr)
}

5. 在路由定义中直接使用正则表达式(推荐)

package main

import (
    "fmt"
    "log"
    "net/http"
    "github.com/julienschmidt/httprouter"
)

func main() {
    router := httprouter.New()
    
    // 直接在路由中使用正则表达式验证UUID
    router.GET("/books/:uuid([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})", BookIndex)
    
    // 或者使用更灵活的正则表达式(支持带或不带连字符)
    router.GET("/items/:uuid([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})", ItemIndex)
    
    log.Fatal(http.ListenAndServe(":8080", router))
}

func BookIndex(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    uuid := ps.ByName("uuid")
    fmt.Fprintf(w, "Book UUID (strict): %s", uuid)
}

func ItemIndex(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    uuid := ps.ByName("uuid")
    fmt.Fprintf(w, "Item UUID (flexible): %s", uuid)
}

这些方法都可以有效地验证HTTP URL中的UUID参数。第一种方法在路由级别进行验证,第二种使用中间件,第三种使用专门的UUID包,最后一种直接在路由定义中使用正则表达式。

回到顶部