【问题标题】:How to get url param in middleware go-chi如何在中间件 go-chi 中获取 url 参数
【发布时间】:2021-12-29 07:27:05
【问题描述】:

我为特定的路由集使用特定的中间件

r.Route("/platform", func(r chi.Router) {
    r.Use(authService.AuthMiddleware)
    r.Get("/{id}/latest", RequestPlatformVersion)
})

现在我如何访问这个AuthMiddleware 中间件中的id url 参数

func (s *Service) AuthMiddleware(h http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
        fmt.Println(chi.URLParam(r, "id"))
        id := chi.URLParam(r, "id")
        
        if id > 100 {
          http.Error(w, errors.New("Error").Error(), http.StatusUnauthorized)
          return
        }
    }
    return http.HandlerFunc(fn)
}

但是,即使正在运行中间件并且正在调用特定路由,id 参数也会打印为空字符串

【问题讨论】:

    标签: go url parameters middleware go-chi


    【解决方案1】:

    您将chi.URLParam 放在路径参数{id} 之前,而您忘记将.ServeHTTP(w, r) 放在中间件中。如果你不放那个东西,你的请求就不会进入 Route 内部的路径中。

    这是工作示例:

    package main
    
    import (
        "fmt"
        "net/http"
    
        "github.com/go-chi/chi"
    )
    
    func AuthMiddleware(h http.Handler) http.Handler {
        fn := func(w http.ResponseWriter, r *http.Request) {
            fmt.Println(chi.URLParam(r, "id"))
            h.ServeHTTP(w, r)
        }
        return http.HandlerFunc(fn)
    }
    
    func main() {
        r := chi.NewRouter()
    
        r.Route("/platform/{id}", func(r chi.Router) {
            r.Use(AuthMiddleware)
            r.Get("/latest", func(rw http.ResponseWriter, r *http.Request) {
                fmt.Println("here ", chi.URLParam(r, "id")) // <- here
            })
        })
    
        http.ListenAndServe(":8080", r)
    }
    

    我将{id} 移动到platform/{id} 以便中间件获得id 路径值,并在中间件中添加h.ServeHTTP(w, r)

    尝试访问http://localhost:8080/platform/1/latest

    输出将是:

    1
    here  1
    

    更新

    在代码之后运行验证不好,你必须修复你定义路径的方式,并在验证后移动.ServeHTTP

    这是一个例子:

    package main
    
    import (
        "errors"
        "fmt"
        "net/http"
        "strconv"
    
        "github.com/go-chi/chi"
    )
    
    func AuthMiddleware(h http.Handler) http.Handler {
        fn := func(w http.ResponseWriter, r *http.Request) {
            fmt.Printf("Middleware First, id: %+v\n", chi.URLParam(r, "id"))
            id, _ := strconv.Atoi(chi.URLParam(r, "id"))
    
            if id > 100 {
                http.Error(w, errors.New("Error").Error(), http.StatusUnauthorized)
                return
            }
            h.ServeHTTP(w, r)
        }
        return http.HandlerFunc(fn)
    }
    
    func main() {
        r := chi.NewRouter()
    
        // This works too ()
        // r.Route("/platform/{id}", func(r chi.Router) {
        //  r.Use(AuthMiddleware)
        //  r.Get("/latest", func(rw http.ResponseWriter, r *http.Request) {
        //      fmt.Println("second: ", chi.URLParam(r, "id")) // <- here
        //  })
        // })
    
        // Other Solution (Wrapping Middleware)
        r.Route("/platform", func(r chi.Router) {
            r.Get("/{id}/latest", AuthMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
                fmt.Println("second: ", chi.URLParam(r, "id")) // <- here
            })).ServeHTTP)
        })
    
        http.ListenAndServe(":8080", r)
    }
    

    【讨论】:

    • 我在中间件中使用了h.ServeHTTP(w, r)。但这只是在尝试检索 url 参数之后。所以,这就是它不起作用的原因。所以,答案也应该是在fmt.Println(chi.URLParam(r, "id")) no 之前使用h.ServeHTTP(w, r)
    • 是的,这个可以。
    • 谢谢。但这总是会成功,对吧?我更新了有问题的代码块,我需要有条件地检查 id 并返回错误。所以,那是做不到的,在这种情况下,可以吗?
    • 不,如果您编写 h.ServeHTTP id 检查,则无法做到这一点。这不是一件好事,先运行代码然后检查验证。为了解决这个问题,我有其他解决方案,将您的RequestPlatformVersion 与您的中间件包装在r.Get 而不是r.Use 中(请参阅更新部分),或者您可以将您的路线更新到r.Route("/platform/{id}", ...),这样您就可以包括中间件,验证后h.ServeHTTP()
    • 我尝试使用中间件的原因是应该检查 /platform/{id} 中的所有路径。但是在每个路由中运行验证意味着,我必须在多个路由中添加相同的逻辑,不是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    • 2020-09-22
    相关资源
    最近更新 更多