英文:
How to implement HandlerFunc without using DefaultServeMux
问题
如果我使用DefaultServeMux(通过将第二个参数传递为nil
来指定),那么我就可以访问http.HandleFunc
,你可以在下面的示例中看到它在Go维基上的使用方式:
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
在我的当前代码中,我无法使用DefaultServeMux,也就是说,我将一个自定义处理程序传递给了ListenAndServe:
h := &mypackage.Handler{
Database: mydb
}
http.ListenAndServe(":8080", h)
因此,我无法使用内置的http.HandleFunc
。然而,我必须将一些授权代码适应到我的代码库中,这需要类似于http.HandleFunc
的东西。例如,如果我一直在使用DefaultServeMux,当我访问"/protected"
路由时,我希望进入Protected
处理程序,但是在通过h.AuthorizationHandlerFunc
之前。像这样:
h.AuthorizationHandlerFunc(Protected)
然而,由于我没有使用DefaultServeMux,它不起作用,也就是说,我无法将Protected
函数传递给AuthorizationHandlerFunc
(并调用它)。下面是AuthorizationHandlerFunc的实现。你可以看到Protected
从未被调用。
问题:在这种情况下(不使用DefaultServeMux),我该如何实现HandlerFunc
?
func (h *Handler) AuthorizationHandlerFunc(next http.HandlerFunc) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
h.AuthorizationMiddleWare(w, r, next)
})
}
func (h *Handler) AuthorizationMiddleWare(w http.ResponseWriter, r *http.Request, next http.HandlerFunc){
//其他操作
log.Println("这里从未被调用")
next(w,r)
}
func (h *Handler)Protected(w http.ResponseWriter, r *http.Request){
log.Println("这里从未被调用")
}
更新
ServeHTTP在mypackage.Handler上实现。为什么Protected函数没有被调用,或者说AuthorizationMiddleWare中的相关代码没有被调用?
英文:
If I were to use the DefaultServeMux (which I designate by passing nil
as the second argument to ListenAndServe), then I have access to http.HandleFunc
, which you see used below in this example from the Go wiki:
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
In my current code, I am not able to use the DefaultServeMux i.e. I'm passing a custom handler to ListenAndServe
h := &mypackage.Handler{
Database: mydb
}
http.ListenAndServe(":8080", h)
so I don't get the http.HandleFunc
built in. However, I have to adapt some authorization code to my code base that requires something like http.HandleFunc
. For example, if I had been using DefaultServeMux, when I hit the "/protected"
route, I would want to go to the Protected
handler, but only after passing through the h.AuthorizationHandlerFunc
like this
h.AuthorizationHandlerFunc(Protected)
However, since I'm not using DefaultServeMux, it's not working i.e. I'm not able to pass the Protected
function (and have it called) to the AuthorizationHandlerFunc
. This is the implementation of the AuthorizationHandlerFunc below. You can see below that Protected
never gets called.
Question: how do I implement HandlerFunc
in this situation (without using DefaultServeMux)?
func (h *Handler) AuthorizationHandlerFunc(next http.HandlerFunc) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
h.AuthorizationMiddleWare(w, r, next)
})
}
func (h *Handler) AuthorizationMiddleWare(w http.ResponseWriter, r *http.Request, next http.HandlerFunc){
//other stuff happens
log.Println("this is never getting called")
next(w,r)
}
func (h *Handler)Protected(w http.ResponseWriter, r *http.Request){
log.Println("this is never getting called")
}
Update
ServeHTTP is implemented on mypackage.Handler. Why is the Protected function not getting called, or, for that matter, the relevant code in the AuthorizationMiddleWare?
答案1
得分: 1
将您的授权中间件重新实现为http.Handler
:
type auth struct {
DB *sql.DB
UnauthorizedHandler http.Handler
}
func NewAuth(db *sql.DB, unauthorized http.Handler) *auth {
return &auth{db, unauthorized}
}
func (a *auth) Protected(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// 检查请求是否有效
// 如果无效,调用错误函数并确保提前*返回*!
if !valid {
a.UnauthorizedHandler.ServeHTTP(w, r)
return
}
// 在成功时调用下一个处理程序
h.ServeHTTP(w, r)
return
}
return http.HandlerFunc(fn)
}
func someHandler(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello!\n")
}
func main() {
auth := NewAuth(db, errorHandler)
r := http.NewServeMux()
// 我们有一个包装了http.HandlerFunc的http.Handler实现
// ...所以我们在ServeMux上调用r.Handle,并对包装的函数进行类型转换
r.Handle("/protected", auth.Protected(http.HandlerFunc(someHandler)))
// 这里只是一个简单的http.HandlerFunc
r.HandleFunc("/public", someOtherHandler)
log.Fatal(http.ListenAndServe(":8000", r))
}
请参考我编写的httpauth库中的示例,其中包含一个具有ServeHTTP
方法的不同示例。上述方法和在类型上显式创建ServeHTTP
方法都是有效的方法。
英文:
Re-implement your authorization middleware as a http.Handler
:
type auth struct {
DB *sql.DB
UnauthorizedHandler http.Handler
}
func NewAuth(db *sql.DB, unauthorized http.Handler) *auth {
return auth{db, unauthorized}
}
func (a *auth) Protected(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// Check whether the request is valid
// If it's invalid, call your error func and make sure to *return* early!
if !valid {
a.UnauthorizedHandler.ServeHTTP(w, r)
return
}
// Call the next handler on success
h.ServeHTTP(w, r)
return
}
return http.HandlerFunc(fn)
}
func someHandler(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello!\n")
}
func main() {
auth := NewAuth(db, errorHandler)
r := http.NewServeMux()
// We have a http.Handler implementation that wraps a http.HandlerFunc
// ... so we call r.Handle on our ServeMux and type-cast the wrapped func
r.Handle("/protected", auth.Protected(http.HandlerFunc(someHandler)))
// Just a simple http.HandlerFunc here
r.HandleFunc("/public", someOtherHandler)
log.Fatal(http.ListenAndServe(":8000", r))
}
Take a look at the httpauth lib I wrote for a different example with a ServeHTTP
method. Both the above and explicitly creating a ServeHTTP
method on your type are valid approaches.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论