How to get url param in middleware go-chi

huangapple go评论73阅读模式
英文:

How to get url param in middleware go-chi

问题

我使用特定的中间件来处理特定的路由。

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参数打印为空字符串。

英文:

I use a specific middleware for specific set of routes

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

Now how can I access id url param inside this AuthMiddleware middleware

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

However, the id param prints as an empty string even though the middleware is being ran and a specific route is being called

答案1

得分: 6

你将chi.URLParam放在路径参数{id}之前,并且忘记在中间件中添加.ServeHTTP(w, r)。如果你不加这个,你的请求将不会进入路由中的路径。

这是一个可工作的示例:

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("中间件先执行,id: %+v\n", chi.URLParam(r, "id"))
		id, _ := strconv.Atoi(chi.URLParam(r, "id"))

		if id > 100 {
			http.Error(w, errors.New("错误").Error(), http.StatusUnauthorized)
			return
		}
		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("second: ", chi.URLParam(r, "id")) // <- here
	// 	})
	// })

	// 另一种解决方案(包装中间件)
	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)
}
英文:

You put your chi.URLParam before the path param {id} and you forgot to put .ServeHTTP(w, r) at the middleware. If you don't put that thing, your request will not go inside the path inside the route.

this is the working example:

package main

import (
	&quot;fmt&quot;
	&quot;net/http&quot;

	&quot;github.com/go-chi/chi&quot;
)

func AuthMiddleware(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		fmt.Println(chi.URLParam(r, &quot;id&quot;))
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func main() {
	r := chi.NewRouter()

	r.Route(&quot;/platform/{id}&quot;, func(r chi.Router) {
		r.Use(AuthMiddleware)
		r.Get(&quot;/latest&quot;, func(rw http.ResponseWriter, r *http.Request) {
			fmt.Println(&quot;here &quot;, chi.URLParam(r, &quot;id&quot;)) // &lt;- here
		})
	})

	http.ListenAndServe(&quot;:8080&quot;, r)
}

I move the {id} to platform/{id} so the middleware got the id path value, and add h.ServeHTTP(w, r) inside the middleware.

try to access http://localhost:8080/platform/1/latest

the output will be:

1
here  1

UPDATE

It is not good to run the validation after the code, you must fix the way you define the path, and move the .ServeHTTP after the validation.

This is the example:

package main

import (
	&quot;errors&quot;
	&quot;fmt&quot;
	&quot;net/http&quot;
	&quot;strconv&quot;

	&quot;github.com/go-chi/chi&quot;
)

func AuthMiddleware(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf(&quot;Middleware First, id: %+v\n&quot;, chi.URLParam(r, &quot;id&quot;))
		id, _ := strconv.Atoi(chi.URLParam(r, &quot;id&quot;))

		if id &gt; 100 {
			http.Error(w, errors.New(&quot;Error&quot;).Error(), http.StatusUnauthorized)
			return
		}
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func main() {
	r := chi.NewRouter()

	// This works too ()
	// r.Route(&quot;/platform/{id}&quot;, func(r chi.Router) {
	// 	r.Use(AuthMiddleware)
	// 	r.Get(&quot;/latest&quot;, func(rw http.ResponseWriter, r *http.Request) {
	// 		fmt.Println(&quot;second: &quot;, chi.URLParam(r, &quot;id&quot;)) // &lt;- here
	// 	})
	// })

	// Other Solution (Wrapping Middleware)
	r.Route(&quot;/platform&quot;, func(r chi.Router) {
		r.Get(&quot;/{id}/latest&quot;, AuthMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			fmt.Println(&quot;second: &quot;, chi.URLParam(r, &quot;id&quot;)) // &lt;- here
		})).ServeHTTP)
	})

	http.ListenAndServe(&quot;:8080&quot;, r)
}

huangapple
  • 本文由 发表于 2021年12月29日 15:27:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/70516345.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定