Serving static content with a root URL with the Gorilla toolkit
Asked Answered
C

5

73

I am attempting to use the Gorilla toolkit's mux package to route URLs in a Go web server. Using this question as a guide I have the following Go code:

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)
}

The directory structure is:

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

The Javascript and CSS files are referenced in index.html like this:

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

When I access http://localhost:8100 in my web browser the index.html content is delivered successfully, however, all the js and css URLs return 404s.

How can I get the program to serve files out of static sub-directories?

Chervonets answered 5/4, 2013 at 12:41 Comment(2)
You might want to see this discussion (not using Gorilla though) about serving static files from root or subdirectories #14086563Erratic
@Ripounet, I did see that question during my research, however, since it was not using Gorilla I was never able to get the ideas to work with my setup where one of my goals was to not have any static files in the root directory of my project (next to main.go). Also, it seems very similar to @Joe's answer below, which also will not work with my setup.Chervonets
S
107

I think you might be looking for 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)
}
Scrivens answered 5/4, 2013 at 13:26 Comment(6)
This was helpful, thank you. I did have a problem trying to get two aliases working though. eg r.PathPrefix("/a/").Handler(http.FileServer(http.Dir("b/"))) r.PathPrefix("/").Handler(http.FileServer(http.Dir("c/"))) In that case, everything in c/ is served, but not b/. Tried a few different subtle variations but to no success. Any ideas?Ennoble
@markdsievers, you might need to strip "/a/" part from the URL. Example: r.PathPrefix("/a/").Handler(http.StripPrefix("/a/", http.FileServer(http.Dir("b")))).Of
Is it possible to add a NotFound handler?Bonnett
the code seems to be similar to my current project code, just a note: the static handler need to be put as last routes, otherwise the other routes's GET will also be covered by that static handler.Superpatriot
This fixed it for me! As @HoangTran mentioned you'll want to set this as the last route. Basically like a "catch-all" if all else fails.Vanscoy
Order is important if you have other handlersMalfeasance
G
53

After a lot of trial and error, both above answers helped me in coming up with what worked for me. I have static folder in web app's root directory.

Along with PathPrefix I had to use StripPrefix for getting route to work recursively.

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)
}

I hope it helps somebody else having problems.

Genesisgenet answered 29/5, 2015 at 11:44 Comment(3)
For anyone using the golang workspace s := ... should read as follows when your working directory is [workspace]/src ... s := http.StripPrefix("/static/", httpFileServer(http.Dir("./web/static/")))Fibrosis
I think, you could also gZip static content there by using some "github.com/lpar/gzipped" or similar library. gzipped.FileServer(http.Dir("./static/"))Civies
it's not working for me, i am getting 404 page not foundTooley
K
10

I have this code here that works quite nice and is re-usable.

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/")
Keeshakeeshond answered 3/6, 2015 at 12:47 Comment(0)
B
5

Try this:

fileHandler := http.StripPrefix("/static/", http.FileServer(http.Dir("/absolute/path/static")))
http.Handle("/static/", fileHandler)
Boodle answered 5/4, 2013 at 13:17 Comment(5)
This would mean changing all the src, href etc attributes to the form "/static/js/jquery.min.js". Although technically would work.Scrivens
Which will allow the JS and CSS files to be loaded, but the index.html file would no longer be available at http://localhost:8100/Chervonets
I usually put all images,css,js etc in static folder.Boodle
The content of the homepage is usually generated dynamically.Boodle
Not if the homepage pulls all dynamic content via JavaScript, then the index.html itself is often completely staticBreastwork
D
0

This serve all files inside the folder flag, as well as serving index.html at the root.

Usage

   //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 ./

Code

    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))
}
Dissertate answered 21/5, 2016 at 18:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.