我有点困惑。许多示例都显示了:http.ServeFile(..)和的用法http.FileServer(..),但似乎它们具有非常紧密的功能。我也没有找到有关如何设置自定义NotFound处理程序的信息。
http.ServeFile(..)
http.FileServer(..)
// This works and strip "/static/" fragment from path fs := http.FileServer(http.Dir("static")) http.Handle("/static/", http.StripPrefix("/static/", fs)) // This works too, but "/static2/" fragment remains and need to be striped manually http.HandleFunc("/static2/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, r.URL.Path[1:]) }) http.ListenAndServe(":8080", nil)
我试图阅读源代码,并且它们都使用serveFile(ResponseWriter, *Request, FileSystem, string, bool)底层函数。但是,http.FileServer返回fileHandler自己的ServeHTTP()方法并在提供文件之前进行一些准备工作(例如path.Clean())。
serveFile(ResponseWriter, *Request, FileSystem, string, bool)
http.FileServer
fileHandler
ServeHTTP()
那么为什么需要这种分离呢?哪种方法更好用?以及如何设置自定义的NotFound处理程序,例如在找不到请求的文件时?
主要区别在于实际上http.FileServer可以将HTTP前缀与文件系统进行几乎1:1的映射。用简单的英语来说,它提供了整个目录路径。以及所有的孩子
假设您有一个名为的目录,/home/bob/static并且您具有以下设置:
/home/bob/static
fs := http.FileServer(http.Dir("/home/bob/static")) http.Handle("/static/", http.StripPrefix("/static", fs))
您的服务器将接受的请求,/static/foo/bar并提供/home/bob/static/foo/bar(或404)处的任何内容
/static/foo/bar
/home/bob/static/foo/bar
相反,它ServeFile是一个较低级别的帮助程序,可用于实现类似于FileServer的功能,或实现自己的可能潜在的麻烦,以及许多其他事情。它只是获取命名的本地文件并通过HTTP连接发送它。就其本身而言,它不会提供整个目录的前缀(除非您编写了一个类似于FileServer进行查找的处理程序)
ServeFile
注意 :天真地为文件系统提供服务是一种潜在的危险(有可能会脱离根目录树),因此,我建议除非您 真的 知道自己在做什么,否则请使用http.FileServer并使用其中http.Dir包括的检查以确保人们可以不要脱离FS,ServeFile事实并非如此。
http.Dir
附录 不幸的是,您的第二个问题,即如何执行自定义的NotFound处理程序,并不容易回答。serveFile正如您所注意到的那样,由于这是从内部函数调用的,因此没有超级容易的地方可以攻入该函数。可能会有一些偷偷摸摸的事情,例如用您自己的ResponseWriter方法拦截响应,从而拦截404响应代码,但我将把练习留给您。
serveFile
ResponseWriter