`http.Handle`和`http.HandleFunc`之间的区别是什么?

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

Difference between http.Handle and http.HandleFunc?

问题

Go文档中对http包有以下示例:

http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})

我有点难以理解Handle和HandleFunc之间的区别,以及为什么需要两个。有人可以用简单明了的话向一个新的Gopher解释一下吗?

英文:

The Go docs have the following example for the http package:

http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})

I'm having sort of a difficulty understanding the difference between Handle and HandleFunc and why two are needed. Can somebody try to explain to a new Gopher in clear words?

答案1

得分: 68

基本上,HTTP服务器的“mux”具有路径 -> 处理程序接口的映射。

这里使用接口,我猜是为了允许您实现具有状态的复杂路径处理程序。

例如,标准包中的file server是一个包含文件服务根目录并实现处理程序接口的结构体。

话虽如此,对于简单的东西,使用函数更简单和更清晰。因此,他们添加了一个特殊的生成器,以便您可以轻松地传递一个函数。

请查看:server.go

从行号:1216(截至今天)

  1216	type HandlerFunc func(ResponseWriter, *Request)
  1217	
  1218	// ServeHTTP calls f(w, r).
  1219	func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
  1220		f(w, r)
  1221	}

他们所做的是在自定义类型上实现接口(恰好与接口的API匹配),并在其中调用自身。

英文:

Basically, the HTTP server's "mux" has a map of path -> handler interface

Interfaces are used here, I assume, to allow you to implement complex path handlers that have state.

For example the file server from the standard package is a struct that contains the root dir for file service and implements the handler interface.

That said, for simple stuff, a func is easier and more clear. So they added a special generator so you can easily pass in a func.

Take a look at: server.go

from line: 1216 (as of today)

  1216	type HandlerFunc func(ResponseWriter, *Request)
  1217	
  1218	// ServeHTTP calls f(w, r).
  1219	func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
  1220		f(w, r)
  1221	}

What they are doing is implementing the interface on a custom type (which happens to match the api of the interface) that just calls itself.

答案2

得分: 44

简单来说:

问题: 我想创建一个能够响应HTTP请求的对象(类型)。

解决方案: 使用http.Handle。它接受一个http.Handler作为第二个参数。
http.Handler是一个接口,应该实现http包中的ServeHTTP方法。


问题: 我想要一个函数来响应我的HTTP请求。

解决方案: 使用http.HandleFunc。它接受一个http.HandlerFunc作为第二个参数。

http.HandlerFunc是一个函数类型,应该实现http包中的ServeHTTP方法。

英文:

In simple terms:

Problem: I want to create an object (type) that responds to HTTP requests.

Solution: Use http.Handle for that. It accepts an http.Handler as the second argument.
http.Handler is an interface and should implement ServeHTTP from the http package.


Problem: I want a function to respond to my HTTP request.

Solution: Use http.HandleFunc for that. It accepts an http.HandlerFunc as the second argument.

http.HandlerFunc is a function type and should implement ServeHTTP from the http package.

答案3

得分: 13

不,它是不同的。让我们来分析一下:

func Handle(pattern string, handler Handler) {
    DefaultServeMux.Handle(pattern, handler) 
}

Handle 函数期望我们传递一个 HandlerHandler 是一个接口:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

如果任何类型实现了 ServeHTTP(ResponseWriter, *Request),例如 myCustomHandler,那么我们可以像这样传递它:Handle(pattern string, myCustomHandler)

在第二种情况下:

HandleFunc(pattern string, func(w ResponseWriter, r *Request) {
    // 做一些操作
}

HandleFunc 期望一个函数,而 Handle 期望一个 Handler 接口。

因此,如果你只想传递一个函数,你可以使用 http.HandleFunc(..)。就像 @David 所展示的,它在内部通过调用 ServeHTTP 来实现 Handler 接口。

type HandlerFunc func(ResponseWriter, *Request)
    
// ServeHTTP 调用 f(w, r)。
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}
英文:

No, it's different. Let's examine:

func Handle(pattern string, handler Handler) {
    DefaultServeMux.Handle(pattern, handler) 
}

Handle expects us to pass a Handler. Handler is an interface

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

if any type implements ServeHTTP(ResponseWriter, *Request) for example:
myCustomHandler then we can pass it like Handle(pattern string, myCustomHandler).

In the second scenario:

HandleFunc(pattern string, func(w ResponseWriter, r *Request) {
    // do some stuff
}

HandleFunc expects a function where Handle expects a Handler interface.

So, if you just want to pass a function then you can use http.HandleFunc(..). Like @David showed that behind the scenes it implements Handler interface by calling ServeHTTP.

type HandlerFunc func(ResponseWriter, *Request)
    
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

答案4

得分: 10

处理程序函数只是创建处理程序的便捷方式。

虽然两者都可以用来创建处理程序,但是因为使用处理程序函数更加简洁,而且同样能够完成工作,为什么还要使用处理程序呢?这归结于设计。如果你有一个现有的接口,或者你想要一个也可以用作处理程序的类型,只需在该接口中添加一个ServeHTTP方法,你就会得到一个可以分配给URL的处理程序。它还可以让你构建更加模块化的Web应用程序。

使用Handle

package main

import (
	"fmt"
	"net/http"
)

type HelloHandler struct{}

func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

type WorldHandler struct{}

func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}

func main() {
	hello := HelloHandler{}
	world := WorldHandler{}
	http.Handle("/hello", &hello)
	http.Handle("/world", &world)
	http.ListenAndServe(":8080", nil)
}

使用HandleFunc

package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

func world(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}

func main() {
	http.HandleFunc("/hello", hello)
	http.HandleFunc("/world", world)
	http.ListenAndServe(":8080", nil)
}

附加信息:

http.Handler是一个具有ServeHTTP()方法的接口,

// net/http/server.go

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

下面是ServeHTTP的信息,

// net/http/server.go

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

// 其中,
// http.ResponseWriter是一个写入器接口,而
// http.Request是一个包含请求详细信息的结构体。

现在让我们看一下HandlerFunc,

// net/http/server.go
// HandlerFunc类型是一个适配器,允许将普通函数用作HTTP处理程序。如果f是具有适当签名的函数,则HandlerFunc(f)是调用f的处理程序。

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP调用f(w, r)。
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

这意味着http.HandlerFunc是一个实现了ServeHTTP方法的类型。

http.HandlerFunc(someFunc)

// 其中,

// 1. someFunc()必须具有以下签名,
func someFunc(w http.ResponseWriter, r *http.Request)

// 2. 这意味着http.HandlerFunc(someFunc)只是将类型http.HandlerFunc强制转换为someFunc()的类型,并不是一个函数调用。

现在让我们来看一下http.Handle(),

// net/http/server.go
// Handle在DefaultServeMux中注册给定模式的处理程序。
// ServeMux的文档解释了如何匹配模式。

func Handle(pattern string, handler Handler) {
	DefaultServeMux.Handle(pattern, handler)
}

通过查看上面的代码片段,你可能已经注意到,第二个参数接受一个Handler接口,这意味着你可以创建任何类型,并为其实现ServeHTTP()方法以满足这个接口。请参考下面的示例证明。

type MyHandler struct{}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World!")
}

func main() {
	handler := MyHandler{}
	http.Handle("/hello", &handler)
	http.ListenAndServe()
}
英文:

Handler functions are merely convenient ways of creating handlers.

While both of them can be used to create handlers, but because, using handler functions is cleaner and it does the job just as well, why use handlers at all? It all boils down to design. If you have an existing interface or if you want a type that can also be used as a handler, simply add a ServeHTTP method to that interface and you’ll get a handler that you can assign to a URL. It can also allow you to
build web applications that are more modular.

Using Handle

package main

import (
	"fmt"
	"net/http"
)

type HelloHandler struct{}

func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

type WorldHandler struct{}

func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}
func main() {
	hello := HelloHandler{}
	world := WorldHandler{}
	http.Handle("/hello", &hello)
	http.Handle("/world", &world)
	http.ListenAndServe(":8080", nil)
}

Using HandleFunc

package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}
func world(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}
func main() {
	http.HandleFunc("/hello", hello)
	http.HandleFunc("/world", world)
	http.ListenAndServe(":8080", nil)
}

Additional information:

http.Handler is an interface with method ServeHTTP(),

// net/http/server.go

type Handler interface {
	 ServeHTTP(ResponseWriter, *Request)
}

And here's a ServeHTTP information,

// net/http/server.go

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

// where,
// http.ResponseWriter is a writer interface, and,
// http.Request is a structure with request details.

Now lets look at HandlerFunc,

// net/http/server.go
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.

type HandlerFunc func(ResponseWriter, *Request)
    
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request){
     f(w, r)
}

That means, http.HandlerFunc is a type that has ServeHTTP method implemented.

http.HandlerFunc(someFunc) 

// where,

// 1. someFunc() must have a signature, 
func someFunc(w http.ResponseWriter, r *http.Request)

// 2. That means, http.HandlerFunc(someFunc) is just a type casting of type http.HandlerFunc on a someFunc() and not a function call.

Now lets go to the http.Handle(),

// net/http/server.go
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.

func Handle(pattern string, handler Handler) { 
     DefaultServeMux.Handle(pattern, handler) 
}

By looking at above snippet, you may have noticed that,
2nd argument accepts a Handler interface, that means, you can create any type and implement a ServeHTTP() method for it to satisfy this. Refer below example for proof.

type MyHandler struct{}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 
    fmt.Fprintf(w, "Hello World!")
}

func main() {
    handler := MyHandler{}
    http.Handle("/hello", &handler)
    http.ListenAndServe()
}

huangapple
  • 本文由 发表于 2014年2月23日 01:06:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/21957455.html
匿名

发表评论

匿名网友

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

确定