使用Gorilla工具包提供带有根URL的静态内容

73

我正在尝试使用Gorilla工具包的mux在Go Web服务器中路由URL。 参考这个问题,我有以下Go代码:

func main() {
    r := mux.NewRouter()
    r.Handle("/", http.FileServer(http.Dir("./static/")))
    r.HandleFunc("/search/{searchTerm}", Search)
    r.HandleFunc("/load/{dataId}", Load)
    http.Handle("/", r)
    http.ListenAndServe(":8100", nil)
}

目录结构如下:

...
main.go
static\
  | index.html
  | js\
     | <js files>
  | css\
     | <css files>

JavaScript 和 CSS 文件在 index.html 中被引用,如下所示:

...
<link rel="stylesheet" href="css/redmond/jquery-ui.min.css"/>
<script src="js/jquery.min.js"></script>
...

当我在浏览器中访问http://localhost:8100时,成功获取到index.html内容,但所有的jscss URL都返回404错误。

我该如何使程序能够提供位于static子目录下的文件?


你可能想看一下这个讨论(虽然没有使用Gorilla),关于从根目录或子目录中提供静态文件的问题。https://dev59.com/ImYq5IYBdhLWcg3w7E6v#14187941 - Deleplace
@Ripounet,我在研究过程中确实看到了这个问题,但由于它没有使用Gorilla,我从未能够将这些思路与我的设置配合使用,在我的设置中,我的一个目标是不在项目的根目录中(main.go旁边)有任何静态文件。此外,它似乎与下面的@Joe's answer非常相似,这也无法在我的设置中工作。 - jason
5个回答

107

我认为你可能正在寻找PathPrefix...

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/search/{searchTerm}", Search)
    r.HandleFunc("/load/{dataId}", Load)
    r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))
    http.ListenAndServe(":8100", r)
}

这很有帮助,谢谢。我遇到了一个问题,尝试让两个别名同时工作。例如 r.PathPrefix("/a/").Handler(http.FileServer(http.Dir("b/"))) r.PathPrefix("/").Handler(http.FileServer(http.Dir("c/"))) 在这种情况下,所有在 c/ 的内容都被服务了,但是 b/ 却没有。尝试了一些微妙的变化,但没有成功。有什么想法吗? - markdsievers
4
@markdsievers,你可能需要从URL中删除"/a/"部分。例如:r.PathPrefix("/a/").Handler(http.StripPrefix("/a/", http.FileServer(http.Dir("b")))) - Roman
1
能否添加一个NotFound处理程序? - Cloom Magoo
2
代码似乎与我的当前项目代码相似,只是需要注意:静态处理程序需要放在最后的路由中,否则“其他”路由的GET也会被该静态处理程序覆盖。 - Hoang Tran
1
这个解决了我的问题!正如@HoangTran提到的,你将想把它设置为最后一个路由。基本上像一个“捕获所有”,如果其他都失败了。 - Christian Gossain
如果你有其他处理程序,顺序很重要。 - Franck

53

经过多次的试错,上面的两个答案都帮助我找到了适合我的解决方案。我在Web应用程序的根目录中有一个静态文件夹。

除了使用PathPrefix之外,我还需要使用StripPrefix来让路由递归工作。

package main

import (
    "log"
    "net/http"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()
    s := http.StripPrefix("/static/", http.FileServer(http.Dir("./static/")))
    r.PathPrefix("/static/").Handler(s)
    http.Handle("/", r)
    err := http.ListenAndServe(":8081", nil)
}

我希望这能帮助其他有问题的人。


对于任何使用golang工作区的人,当您的工作目录为[workspace]/src时,s := ...应该读作以下内容:s := http.StripPrefix("/static/", httpFileServer(http.Dir("./web/static/"))) - Frito
我认为,您可以使用一些“github.com/lpar/gzipped”或类似的库来压缩静态内容。 gzipped.FileServer(http.Dir("./static/")) - Dzintars
1
它对我不起作用,我得到了404页面未找到的错误。 - deeptimancode

10

我有一份代码,它非常好用且可重复使用。

func ServeStatic(router *mux.Router, staticDirectory string) {
    staticPaths := map[string]string{
        "styles":           staticDirectory + "/styles/",
        "bower_components": staticDirectory + "/bower_components/",
        "images":           staticDirectory + "/images/",
        "scripts":          staticDirectory + "/scripts/",
    }
    for pathName, pathValue := range staticPaths {
        pathPrefix := "/" + pathName + "/"
        router.PathPrefix(pathPrefix).Handler(http.StripPrefix(pathPrefix,
            http.FileServer(http.Dir(pathValue))))
    }
}
router := mux.NewRouter()
ServeStatic(router, "/static/")

5
尝试这个:
fileHandler := http.StripPrefix("/static/", http.FileServer(http.Dir("/absolute/path/static")))
http.Handle("/static/", fileHandler)

这意味着将所有 srchref 等属性更改为形式 "/static/js/jquery.min.js"。虽然从技术上讲,起作用。 - Chris Farmiloe
这将允许JS和CSS文件被加载,但index.html文件将不再在http://localhost:8100/上可用。 - jason
我通常将所有的 imagescssjs 等文件放在 static 文件夹中。 - Joe
主页的内容通常是动态生成的。 - Joe
如果主页通过JavaScript获取所有动态内容,则index.html本身通常完全静态。 - Niklas Schnelle

0

这将服务于 flag 文件夹中的所有文件,并在根目录下提供 index.html。

用法

   //port default values is 8500
   //folder defaults to the current directory
   go run main.go 

   //your case, dont forget the last slash
   go run main.go -folder static/

   //dont
   go run main.go -folder ./

代码

    package main

import (
    "flag"
    "fmt"
    "net/http"
    "os"
    "strconv"
    "strings"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
    "github.com/kr/fs"
)

func main() {
    mux := mux.NewRouter()

    var port int
    var folder string
    flag.IntVar(&port, "port", 8500, "help message for port")
    flag.StringVar(&folder, "folder", "", "help message for folder")

    flag.Parse()

    walker := fs.Walk("./" + folder)
    for walker.Step() {
        var www string

        if err := walker.Err(); err != nil {
            fmt.Fprintln(os.Stderr, "eroooooo")
            continue
        }
        www = walker.Path()
        if info, err := os.Stat(www); err == nil && !info.IsDir() {
            mux.HandleFunc("/"+strings.Replace(www, folder, "", -1), func(w http.ResponseWriter, r *http.Request) {
                http.ServeFile(w, r, www)
            })
        }
    }
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        http.ServeFile(w, r, folder+"index.html")
    })
    http.ListenAndServe(":"+strconv.Itoa(port), handlers.LoggingHandler(os.Stdout, mux))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接