我在 FileServer 的根目录有什么不同吗?

Does it make a difference where I root a FileServer?

https://www.alexedwards.net/blog/serving-static-sites-with-go,有一个静态文件服务器在单个目录中为站点提供服务的示例:static

File: app.go
...
func main() {
  fs := http.FileServer(http.Dir("static"))
  http.Handle("/static/", http.StripPrefix("/static/", fs))

  log.Println("Listening...")
  http.ListenAndServe(":3000", nil)
}

但是,我发现我可以通过以下方式获得相同的结果。

func main() {
  fs := http.FileServer(http.Dir(".")) // root at the root directory.
  http.Handle("/static/", fs) //leave off the StripPrefix call.

  log.Println("Listening...")
  http.ListenAndServe(":3000", nil)
}

这样做有任何(性能或安全)缺点吗?我可以看到,如果我在文件系统上的文件位置与它们所服务的 URL 不匹配,我将不得不使用 StripPrefix,但在这种情况下,似乎调用 StripPrefix 是不必要的。

编辑: 我忘了说了,不过我自己已经看过了。在性能方面,这似乎不是问题,因为对 FileServer 的调用实际上并没有将文件加载到内存中;它只是存储地址。在安全方面,这似乎完全相同:我尝试使用类似以下内容的目录遍历攻击。

$ curl -i --path-as-is 'http://localhost:3000/static/../sensitive.txt'

但是我对两个版本都得到了 301 响应,这让我有点吃惊。

当你使用http.ServeMux处理程序时也是如此

http.ServeMux 会在匹配路径前调用 cleanPath 函数

https://github.com/golang/go/blob/master/src/net/http/server.go#L2305

func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
// snip
    path := cleanPath(r.URL.Path)
//snip
}  

cleanPath 函数 return p 的规范路径,消除 .和 .. 元素。

https://github.com/golang/go/blob/master/src/net/http/server.go#L2174-L2193

// cleanPath returns the canonical path for p, eliminating . and .. elements.

func cleanPath(p string) string {
    if p == "" {
        return "/"
    }
    if p[0] != '/' {
        p = "/" + p
    }
    np := path.Clean(p)
    // path.Clean removes trailing slash except for root;
    // put the trailing slash back if necessary.
    if p[len(p)-1] == '/' && np != "/" {
        // Fast path for common case of p being the string we want:
        if len(p) == len(np)+1 && strings.HasPrefix(p, np) {
            np = p
        } else {
            np += "/"
        }
    }
    return np
}