在 http.FileServer 中覆盖 Last-Modified header
Overriding Last-Modified header in http.FileServer
我试图覆盖 http.FileServer
设置的 Last-Modified
-header,但它恢复到我正在尝试的文件的 Last-Modified
-时间服务:
var myTime time.Time
func main() {
myTime = time.Now()
fs := http.StripPrefix("/folder/", SetCacheHeader(http.FileServer(http.Dir("/folder/"))))
http.Handle("/folder/", fs)
http.ListenAndServe(":80", nil)
}
我的 SetCacheHeader
-处理程序:
func SetCacheHeader(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Last-Modified", myTime.Format(http.TimeFormat))
h.ServeHTTP(w, r)
})
}
由 http.FileServer()
编写的处理程序 return 无条件地在 http.serveFile()
和 http.serveContent()
未导出函数中设置 "Last-Modified"
header:
func serveFile(w ResponseWriter, r *Request, fs FileSystem,
name string, redirect bool) {
// ...
f, err := fs.Open(name)
// ...
d, err := f.Stat()
// ...
// serveContent will check modification time
sizeFunc := func() (int64, error) { return d.Size(), nil }
serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
}
func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
sizeFunc func() (int64, error), content io.ReadSeeker) {
setLastModified(w, modtime)
// ...
}
func setLastModified(w ResponseWriter, modtime time.Time) {
if !isZeroTime(modtime) {
w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
}
}
因此您在调用文件服务器处理程序之前设置的内容将被覆盖。你对此无能为力。
如果您需要以自定义 last-modified 时间提供文件内容,您可以使用 http.ServeContent()
:
func ServeContent(w ResponseWriter, req *Request, name string,
modtime time.Time, content io.ReadSeeker)
在这里你可以通过last-modified时间来使用,但是你当然会失去http.FileServer()
提供的所有便利功能。
如果您想继续使用 http.FileServer()
,另一种选择是不使用您传递给 http.FileServer()
的 http.Dir
type, but create your own http.FileSystem
实现,您可以在其中报告任何 [=51] =] 你想要的时间戳。
这需要您实现以下接口:
type FileSystem interface {
Open(name string) (File, error)
}
所以你需要一个按文件名打开文件的方法,returns 一个实现 http.File
的值,即:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
而您 return 的值(实现 http.File
)可以有一个 Stat() (os.FileInfo, error)
方法实现,其 os.FileInfo
returned value contains the last-modified time of your choosing. Note that you should also implement the Readdir()
method to return custom last-modified timestamps consistent with the timestamps returned by Stat()
's fileinfo. See related question how to do that: Simples way to make a []byte into a "virtual" File object in golang?
我试图覆盖 http.FileServer
设置的 Last-Modified
-header,但它恢复到我正在尝试的文件的 Last-Modified
-时间服务:
var myTime time.Time
func main() {
myTime = time.Now()
fs := http.StripPrefix("/folder/", SetCacheHeader(http.FileServer(http.Dir("/folder/"))))
http.Handle("/folder/", fs)
http.ListenAndServe(":80", nil)
}
我的 SetCacheHeader
-处理程序:
func SetCacheHeader(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Last-Modified", myTime.Format(http.TimeFormat))
h.ServeHTTP(w, r)
})
}
由 http.FileServer()
编写的处理程序 return 无条件地在 http.serveFile()
和 http.serveContent()
未导出函数中设置 "Last-Modified"
header:
func serveFile(w ResponseWriter, r *Request, fs FileSystem,
name string, redirect bool) {
// ...
f, err := fs.Open(name)
// ...
d, err := f.Stat()
// ...
// serveContent will check modification time
sizeFunc := func() (int64, error) { return d.Size(), nil }
serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
}
func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
sizeFunc func() (int64, error), content io.ReadSeeker) {
setLastModified(w, modtime)
// ...
}
func setLastModified(w ResponseWriter, modtime time.Time) {
if !isZeroTime(modtime) {
w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
}
}
因此您在调用文件服务器处理程序之前设置的内容将被覆盖。你对此无能为力。
如果您需要以自定义 last-modified 时间提供文件内容,您可以使用 http.ServeContent()
:
func ServeContent(w ResponseWriter, req *Request, name string,
modtime time.Time, content io.ReadSeeker)
在这里你可以通过last-modified时间来使用,但是你当然会失去http.FileServer()
提供的所有便利功能。
如果您想继续使用 http.FileServer()
,另一种选择是不使用您传递给 http.FileServer()
的 http.Dir
type, but create your own http.FileSystem
实现,您可以在其中报告任何 [=51] =] 你想要的时间戳。
这需要您实现以下接口:
type FileSystem interface {
Open(name string) (File, error)
}
所以你需要一个按文件名打开文件的方法,returns 一个实现 http.File
的值,即:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
而您 return 的值(实现 http.File
)可以有一个 Stat() (os.FileInfo, error)
方法实现,其 os.FileInfo
returned value contains the last-modified time of your choosing. Note that you should also implement the Readdir()
method to return custom last-modified timestamps consistent with the timestamps returned by Stat()
's fileinfo. See related question how to do that: Simples way to make a []byte into a "virtual" File object in golang?