How does httprouterhttp.HandlerFunc() works?

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

How does httprouterhttp.HandlerFunc() works?

问题

我正在学习Go语言,并且目前正在尝试理解julienschmidt的httprouter路由器的工作原理,特别是router.HandlerFunc()的工作原理。

Go的http包:

  • http.Handler:Handler是一个接口。任何具有相同方法签名(即ServeHTTP(w, r))的类型都可以实现Handler接口。
  • http.Handle:http.Handle是一个函数,它有两个参数。1)用于匹配请求路径的字符串,2)Handler,用于调用其ServeHTTP()方法。
  • http.HandlerFunc:一个具有函数签名(ResponseWriter, *Request)和自己的ServeHTTP(w, r)方法的自定义函数类型,它满足http.Handler接口。

现在,如果我需要使用一个满足HandlerFunc的函数,比如Bar(ResponseWriter, *Request),在http.Handle中,我需要将该函数强制转换为http.HandlerFunc,然后在http.Handle中使用它,就像这样:

func Bar(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("My bar func response"))
}
...
mf := http.HandlerFunc(Bar)
http.Handle("/path", mf)
  • 查看http.HandleFunc的源代码,可以看到http.HandleFunc()的工作原理。它期望一个具有(w ResponseWriter, r *Request)签名的函数,并将该函数强制转换为HandlerFunc类型。

像这样:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}

julienschmidt的httprouter

查看router.HandlerFunc()的源代码

func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
    r.Handler(method, path, handler)
}
  • 与http.HandleFunc()不同,它不期望一个具有适当签名(ResponseWriter, *Request)的函数,而是期望一个http.HandlerFunc。
  • 而且,它不需要将函数强制转换为HandlerFunc类型,只需将函数传递给另一个函数router.Handler(method, path string, handler http.Handler),该函数又期望一个Handler。

所以,我可以毫无问题地执行这段代码:

router.HandlerFunc(http.MethodPost, "/path", Bar) // Bar没有被强制转换为HandlerFunc

我可以理解将Bar强制转换为HandlerFunc,然后将其传递给router.HandlerFunc()。

请帮我解答一些疑问:

  1. 如果没有将Bar()强制转换为HandlerFunc,它如何满足router.HandlerFunc()的HandlerFunc类型?
  2. 如果router.Handler()期望一个http.Handler类型,那么没有将Bar()强制转换为http.HandlerFunc,它如何满足router.Handler()的Handler类型?
  3. 我漏掉了什么?
英文:

I am learning Go and at the moment trying to understand what and how actually julienschmidt's httprouterhttp router works. Especially how the router.HandlerFunc() works.

Go's http package:

  • http.Handler: Handler is an Interface. Any type which has the same method signature i.e., ServeHTTP(w,r) implements a Handler.
  • http.Handle: http.Handle is a function which has two parameters. 1) String to match request path, 2)Handler, to call its ServeHTTP() method.
  • http.HandlerFunc: A custom function type with function signature (ResponseWriter, *Request) and its own ServeHTTP(w,r) method, which satisfies as a http.Handler interface.

Now if I need to use a function eg. Bar(ResponseWriter, *Request) which satisfies to be a HandlerFunc, inside http.Handle, I type caste/covert the function to http.HandlerFunc and then use it inside the http.Handle. Like so:

func Bar(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("My bar func response"))
}
...
mf := http.HandlerFunc(Bar)
http.Handle("/path", mf)
  • Looking at the http.HandleFunc source code, this is how http.HandleFunc() works. It expects a function which as the signature of (w ResponseWriter, r *Request) and type caste the function.

Like so:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))
}

julienschmidt's httprouterhttp

Looking at the source code of router.HandlerFunc()

func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
	r.Handler(method, path, handler)
}
  • Instead of expecting a function with appropriate signature (ResponseWriter, *Request) like the http.HandleFunc(), it expects a http.HandlerFunc.
  • Also without type casting/converting the function to a HandlerFunc type, it just pass the function to another function router.Handler(method, path string, handler http.Handler), which again expects a Handler.

So I can execute this code without any problem:

router.HandlerFunc(http.MethodPost, "/path", Bar) // Bar is not type casted/converted to a HandlerFunc

I can understand type casting the Bar to a HandlerFunc and then pass it to router.HandlerFunc().

Could you please clear some of my doubts:

  1. How does without type casting the Bar() to a HandlerFunc satisfies as a HandlerFunc type to the router.HandlerFunc()?
  2. If the router.Handler() expects a http.Handler type, how come Bar() without type casting to the http.HandlerFunc satisfies a a Handler to the router.Handler()?
  3. What am I missing?

答案1

得分: 3

  1. 不需要将Bar()转换为HandlerFunc类型,它仍然可以满足作为HandlerFunc类型传递给router.HandlerFunc()的要求。

表达式

router.HandlerFunc(http.MethodPost, "/path", Bar)

符合可赋值性规则

VT具有相同的底层类型,并且VT中至少有一个不是命名类型。

Bar函数的类型和http.HandlerFunc类型具有相同的底层类型,并且Bar的类型不是命名类型。因此,你可以将Bar作为handler参数传递(赋值)给httprouter.Router.HandlerFunc,而无需进行显式转换


  1. 如果router.Handler()期望一个http.Handler类型,那么为什么Bar()不需要转换为http.HandlerFunc类型就可以满足作为handler传递给router.Handler()的要求?

在以下方法定义中

func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
    r.Handler(method, path, handler)
}

没有Bar,只有类型为http.HandlerFunchandler参数,而该类型实现了http.Handler接口。因此,语句r.Handler(method, path, handler)是完全合法的。


  1. 你可能忽略了上述内容。
英文:
  1. "How does without type casting the Bar() to a HandlerFunc satisfies as a HandlerFunc type to the router.HandlerFunc()?"

The expression

router.HandlerFunc(http.MethodPost, "/path", Bar)

complies with the rules of Assignability:

> V and T have identical underlying types and at least one of V or T is not a named type.

The Bar function's type and the http.HandlerFunc type have identical underlying types, and Bar's type is not named. Because of that you can pass (assign) Bar as the handler argument to httprouter.Router.HandlerFunc without an explicit conversion.


  1. "If the router.Handler() expects a http.Handler type, how come Bar() without type casting to the http.HandlerFunc satisfies a a Handler to the router.Handler()?"

In the following method definition

func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
    r.Handler(method, path, handler)
}

there is no Bar, there's only the handler argument whose type is http.HandlerFunc and that type does implement the http.Handler interface. So the statement r.Handler(method, path, handler) is perfectly legitimate.


  1. "What am I missing?"

See above.

答案2

得分: 0

看一下HandlerFunc的定义:

type HandlerFunc func(ResponseWriter, *Request)

以及你的函数的签名:

(w http.ResponseWriter, r *http.Request)

这里不需要进行转换。

英文:

Look at definition of HandlerFunc

type HandlerFunc func(ResponseWriter, *Request)

And the signature of your function

(w http.ResponseWriter, r *http.Request)

You don't need conversion here.

huangapple
  • 本文由 发表于 2022年6月18日 17:25:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/72668157.html
匿名

发表评论

匿名网友

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

确定