How to implement HandlerFunc without using DefaultServeMux

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

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.

huangapple
  • 本文由 发表于 2015年9月1日 19:44:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/32330744.html
匿名

发表评论

匿名网友

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

确定