0
votes

I can't seem to get my routing right. I'm using Gorilla Mux and I'm trying to serve my angular app, so basically my index.html, from any url except them starting with "/foo".

This one works:

func StaticFileServer(w http.ResponseWriter, r *http.Request) {
  http.ServeFile(w, r, config.dir)
}

func main() {

  fs := http.Dir(config.dir)
  fileHandler := http.FileServer(fs)

  router = mux.NewRouter()

  router.Handle("/foo/page", PublicHandler(handler(getAll)).Methods("GET")
  router.Handle("/foo/page/{id}", PublicHandler(handler(getOne)).Methods("GET")

  router.PathPrefix("/{blaah}/{blaah}/").Handler(fileHandler)
  router.PathPrefix("/").HandlerFunc(StaticFileServer)

  ...
}

But there must be an easier way than to explicitly declaring every possible route, like this PathPrefix("/{blaah}/{blaah}/") thingy... With this one, any other url than /{blaah}/{blaah}/ returns a 404 page not found, instead of index.html.

So I'd like to get everything served (static files etc.) as long as they can be found, but everything else should return /public/index.html.

2
no. it makes every URL asked by client that is NOT DEFINED in gorilla router to serve in response the index.html file - thus letting Your angualr app handle routing other then API calls (ui-router, ngRoute) :).Jarema

2 Answers

1
votes

I was also facing the same issue but if we use Gorilla mux we have a clear solution for this.

Because Angular is a single page application so we have to handle that way. I have two folders client and server. Inside client folder I keep my all angular code and inside server folder I keep all server code so static path to render index.html is "client/dist". Here dist folder is a angular build folder.

Go router code is given below-

 func main {
        router := mux.NewRouter()
        spa := spaHandler{staticPath: "client/dist", indexPath: "index.html"}
        router.PathPrefix("/").Handler(spa)
}

spaHandler implements the http.Handler interface, so we can use it to respond to HTTP requests. The path to the static directory and path to the index file within that static directory are used to serve the SPA in the given static directory.

type spaHandler struct {
    staticPath string
    indexPath  string
}

ServeHTTP inspects the URL path to locate a file within the static dir on the SPA handler. If a file is found, it will be served. If not, the file located at the index path on the SPA handler will be served. This is suitable behavior for serving an SPA (single page application).

func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

    // get the absolute path to prevent directory traversal
    path, err := filepath.Abs(r.URL.Path)
    if err != nil {
        // if we failed to get the absolute path respond with a 400 bad request
        // and stop
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // prepend the path with the path to the static directory
    path = filepath.Join(h.staticPath, path)

    // check whether a file exists at the given path
    _, err = os.Stat(path)
    if os.IsNotExist(err) {
        // file does not exist, serve index.html
        http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath))
        return
    } else if err != nil {
        // if we got an error (that wasn't that the file doesn't exist) stating the
        // file, return a 500 internal server error and stop
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // otherwise, use http.FileServer to serve the static dir
    http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r)
}
0
votes

I'm a bit late, but other people may find my answer useful.

Basically Gorilla Mux is doing all of your routings here. I'm assuming you want AngularJS to do the routing for any URL that doesn't start with "/foo".

You can use regex to send any requests that doesn't start with "/foo" to your index.html using:

router.PathPrefix("/{_:.*}").HandlerFunc(StaticFileServer)