覆盖http.FileServer中的Last-Modified标头

sal*_*ent 3 last-modified go http-headers

我试图覆盖Last-Modified-header设置http.FileServer,但它恢复到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)
}
Run Code Online (Sandbox Code Playgroud)

我的处理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)
    })
}
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 6

http.FileServer()无条件返回的处理程序"Last-Modified"http.serveFile()http.serveContent()未导出的函数中设置标题:

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))
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,在调用文件服务器处理程序之前设置的内容将被覆盖.你无法对此做任何事情.

如果您需要使用自定义的上次修改时间来提供文件内容,您可以使用http.ServeContent():

func ServeContent(w ResponseWriter, req *Request, name string,
    modtime time.Time, content io.ReadSeeker)
Run Code Online (Sandbox Code Playgroud)

你可以通过最后修改时间来使用,但当然你失去了所提供的所有便利功能http.FileServer().

如果您想继续使用http.FileServer(),另一种选择是不使用该http.Dir类型,而是创建您http.FileSystem传递给的自己的实现,您可以http.FileServer()在其中报告您希望的任何上次修改的时间戳.

这将要求您实现以下接口:

type FileSystem interface {
        Open(name string) (File, error)
}
Run Code Online (Sandbox Code Playgroud)

所以你需要一个按名称打开文件的方法,并返回一个实现的值http.File,即:

type File interface {
        io.Closer
        io.Reader
        io.Seeker
        Readdir(count int) ([]os.FileInfo, error)
        Stat() (os.FileInfo, error)
}
Run Code Online (Sandbox Code Playgroud)

并且您返回的值(实现http.File)可以具有Stat() (os.FileInfo, error)方法实现,其os.FileInfo返回值包含您选择的最后修改时间.请注意,您还应该实现该Readdir()方法以返回与Stat()fileinfo 返回的时间戳一致的自定义上次修改时间戳.请参阅相关问题如何操作:在golang中将[]字节变为"虚拟"File对象的简单方法?