在 Go 语言中,有几个内置的 Handler ,这一期就来简单介绍一下这几个 Handler 。
http.NotFoundHandler
NotFoundHandler
返回一个 handler ,它给每个请求的响应都是 "404 page not found"
。
// NotFoundHandler returns a simple request handler
// that replies to each request with a ``404 page not found'' reply.
func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
// NotFound replies to the request with an HTTP 404 not found error.
func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
下面是一个例子:
package main
import (
"fmt"
"net/http"
)
func myHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "This is my handler.")
})
}
func main() {
mux := http.NewServeMux()
mux.Handle("/a", http.NotFoundHandler())
mux.Handle("/b", myHandler())
http.ListenAndServe(":8080", mux)
}
运行后在浏览器访问 http://localhost:8080/a
会响应 "404 page not found"
;访问 http://localhost:8080/b
会响应 "This is my handler."
。
http.RedirectHandler
RedirectHandler
是用来跳转的,它有两个参数:
url
是 string 类型的,表示要跳转到的 URL ;code
状态码(3XX),是 int 类型的,常见的有:StatusMovedPermanently
、 StatusFound
或 StatusSeeOther
等。RedirectHandler
返回的是一个 handler ,它把每个请求使用给定的状态码跳转到指定的 URL 。
// RedirectHandler returns a request handler that redirects
// each request it receives to the given url using the given
// status code.
//
// The provided code should be in the 3xx range and is usually
// StatusMovedPermanently, StatusFound or StatusSeeOther.
func RedirectHandler(url string, code int) Handler {
return &redirectHandler{url, code}
}
// Redirect to a fixed URL
type redirectHandler struct {
url string
code int
}
http.StripPrefix
StripPrefix
有两个参数:
prefix
是 string 类型的,表示 URL 将要被移除的字符串前缀;h
是一个 handler ,在移除字符串前缀之后,这个 handler 将会接收到请求。StripPrefix
返回一个 handler ,它从请求 URL 中去掉指定的前缀,然后再调用另一个 handler 。如果请求的 URL 与提供的前缀不符,那么响应 "404 page not found"
。
// StripPrefix returns a handler that serves HTTP requests by removing the
// given prefix from the request URL's Path (and RawPath if set) and invoking
// the handler h. StripPrefix handles a request for a path that doesn't begin
// with prefix by replying with an HTTP 404 not found error. The prefix must
// match exactly: if the prefix in the request contains escaped characters
// the reply is also an HTTP 404 not found error.
func StripPrefix(prefix string, h Handler) Handler {
if prefix == "" {
return h
}
return HandlerFunc(func(w ResponseWriter, r *Request) {
p := strings.TrimPrefix(r.URL.Path, prefix)
rp := strings.TrimPrefix(r.URL.RawPath, prefix)
if len(p) < len(r.URL.Path) && (r.URL.RawPath == "" || len(rp) < len(r.URL.RawPath)) {
r2 := new(Request)
*r2 = *r
r2.URL = new(url.URL)
*r2.URL = *r.URL
r2.URL.Path = p
r2.URL.RawPath = rp
h.ServeHTTP(w, r2)
} else {
NotFound(w, r)
}
})
}
http.TimeoutHandler
TimeoutHandler
有三个参数:
h
,是将要被修饰的 handler ;dt
,是 time.Duration 类型的,是第一个 handler 允许的处理时间;msg
是 string 类型的,表示如果超时,那么就把 msg 返回给请求,表示响应时间过长。它返回一个 handler ,它用来在指定时间内运行传入的 h ,相当于是一个修饰器。
// TimeoutHandler returns a Handler that runs h with the given time limit.
//
// The new Handler calls h.ServeHTTP to handle each request, but if a
// call runs for longer than its time limit, the handler responds with
// a 503 Service Unavailable error and the given message in its body.
// (If msg is empty, a suitable default message will be sent.)
// After such a timeout, writes by h to its ResponseWriter will return
// ErrHandlerTimeout.
//
// TimeoutHandler supports the Pusher interface but does not support
// the Hijacker or Flusher interfaces.
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
return &timeoutHandler{
handler: h,
body: msg,
dt: dt,
}
}
http.FileServer
FileServer
返回一个 handler ,使用基于 root 的文件系统来响应请求。
func FileServer(root FileSystem) Handler {
return &fileHandler{root}
}
root
是一个 FileSystem ,是一个接口,接口里面有一个 Open 方法,该方法有一个 name 参数,该参数是 string 类型的,该方法返回一个 File 文件或者是 error 错误。
// A FileSystem implements access to a collection of named files.
// The elements in a file path are separated by slash ('/', U+002F)
// characters, regardless of host operating system convention.
// See the FileServer function to convert a FileSystem to a Handler.
//
// This interface predates the fs.FS interface, which can be used instead:
// the FS adapter function converts an fs.FS to a FileSystem.
type FileSystem interface {
Open(name string) (File, error)
}
使用时需要用到操作系统的文件系统,还需要委托给:
type Dir string
Dir 也实现了 Open 接口。
// Open implements FileSystem using os.Open, opening files for reading rooted
// and relative to the directory d.
func (d Dir) Open(name string) (File, error) {
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
return nil, errors.New("http: invalid character in file path")
}
dir := string(d)
if dir == "" {
dir = "."
}
fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
f, err := os.Open(fullName)
if err != nil {
return nil, mapDirOpenError(err, fullName)
}
return f, nil
}
下面是一个例子,我们在 main 目录下新建 wwwroot 目录,在此目录下存放网站的 html 以及相关的 css 和 js 文件,我们的目的是要通过浏览器访问目录下 index.html 文件:
package main
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 第三个参数是想要得到的文件的名字 要加前缀
http.ServeFile(w, r, "main/wwwroot" + r.URL.Path)
})
http.ListenAndServe(":8080", nil)
}
运行上面的程序,通过浏览器访问 http://localhost:8080
就能访问 main/wwwroot 目录下的 index.html 文件,并能加载相关的样式文件。
当然,我们能简化上面的程序:
package main
import "net/http"
func main() {
http.ListenAndServe(":8080", http.FileServer(http.Dir("main/wwwroot")))
}
运行这段代码同样会得到相同的结果。
👇希望对你有帮助,期待你的关注👇
联系客服