静态资源通过Handle来注册源码如下
// Handle registers the handler for the given pattern // in the DefaultServeMux. // The documentation for ServeMux explains how patterns are matched. func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }pattern与Handler一一匹配
静态资源中一般是注册一个静态资源目录到一个对应的uri下面
比如
pwd,_ := os.Getwd() http.Handle("/", http.FileServer(http.Dir(filepath.Join(pwd, "src/view"))))这里有一点要注意os.Getwd()获取的是项目的路径然后再加上对应的静态资源路径也就是说这里其实注册了一个绝对路径
这里之所以会写绝对路径是因为写相对路径一直就报错404 无奈之下去查看源码
(因为相对路径导致的404问题已经解决因为当时我用的时idea并不是在命令行go run启的程序所以执行路径就不是当前目录
而程序中指定的相对路径是针对于执行路径的所以静态资源文件就找不到了
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go)
源码中真正访问静态资源的代码如下
type Dir string func (d Dir) Open(name string) (File, error) { if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || strings.Contains(name, "\x00") { return nil, errors.New("http: invalid character in file path") } dir := string(d) if dir == "" { dir = "." } <span style="color:#ff0000;">f, err := os.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))))</span> if err != nil { return nil, err } return f, nil }请注意红色标注的是真正去访问静态资源的代码 这里os.Open的路径其实就是
dir + 传进来的name那这个dir是什么呢 就是一开始我们注册的路径 源码如下
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) { upath := r.URL.Path if !strings.HasPrefix(upath, "/") { upath = "/" + upath r.URL.Path = upath } <span style="color:#ff0000;">serveFile(w, r, f.root, path.Clean(upath), true)</span> }
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) { //...... <span style="color:#ff0000;">f, err := fs.Open(name)</span> //...... }f.root就是之前的http.Dir 而http.Dir 实现了FileSystem的open方法所以也可以被当做FileSystem类型传入
Dir就是之前注册的静态资源目录 serveFile中name 及对应的uri 红色标注的fs.open(name)传入的就是用户访问的uri路径
实际上就是调用Dir的Open方法 在Dir的open方法中 通过os包下的Open去访问静态资源文件
但是这个os.Open的访问规则我还是不太明确 比如我写/view是相对main.go的目录是平级的但是os.Open就是无法找到
所以很无奈只能通过os.Getwd获取绝对路径来解决这个问题
如果有哪位大虾指导os.Open针对相对路径是如何做处理的 望能解惑
下面记录一些在我查看源码是碰到的一些标准库的基本用法
path
path.Clean(name string) string
该方法返回最短的有效路径名
/say ---> /say
1 ///say ---> /say
2 ./say ---> say
3 view/../say ---> say
4 "" ----> "."
filepath
filepath.FromSlash()
该方法将所有的/替换成系统的分割线
filepath.Join(em...string)
将多个路径连接在一起
比如
/say /view ---> /say/view
/say view --->/say/view
os.Args[0] 获取程序执行的路径名
os.GetWd() 获取当前项目的路径
有疑问加站长微信联系(非本文作者)