I have some html files in folder /html (for example main.html,page1.html, page2.html,etc ). And I serve it, using next Go code
r := mux.NewRouter()
r.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir(htmlDir))))
So if I open address http://127.0.0.1/page1.html, then page1.html will be shown( it is what I need).
But I also want to bind address http://127.0.0.1/ to main.html. How can I do it?
I can rename main.html to index.html, but I think it is not true way.
You could additionally add a HandlerFunc to handle that:
r := mux.NewRouter()
r.HandleFunc("/", homeHandler)
r.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir(htmlDir))))
In the homeHandler you serve the file you want to serve:
func homeHandler(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, fmt.Sprintf("./%s/index.htm", htmlDir))
}
There might be other options...
Related
I want to display a compiled angular project under a subpath (eg http://localhost:3000/app/) with go mux
It works as expected without the subpath "app/"
But when I add the subpath with http.StripPrexix("/app/, ..) Handler only index html is found and rendered but without all css, js files..
Test code
package main
import (
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
mux := mux.NewRouter()
fs := http.FileServer(http.Dir("./static/"))
// Serve static files
mux.PathPrefix("/app/").Handler(http.StripPrefix("/app/", fs))
log.Println("Listening...")
http.ListenAndServe(":3000", mux)
}
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>TestProject</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.3ff695c00d717f2d2a11.css"></head>
<body>
<h1>Should work</h1>
<app-root></app-root>
<script src="runtime.359d5ee4682f20e936e9.js" defer></script><script src="polyfills.bf99d438b005d57b2b31.js" defer></script><script src="main.5dd083c1a27b2a7e410a.js" defer></script></body>
</html>
Working Project Download
This project also includes the static files to serve
https://filehorst.de/d/dubJmmsz
Goal
Serve different projects under different paths
Following on this question
What am I doing wrong?
How to serve the whole project under e.g.: localhost:3000/app/
The gorilla mux docs mention how to handle Angular SPA applications.
However since you want to base your SPA root to a sub directory, you also need to do the changes in HTML/JS. The base directory should be a variable that will be same as that of prefix of SPA. This is more of a design problem I believe
Otherwise since your rest of the files other than index are resolved at root you need to fallback to "/" for rest of the files & have both configured.
router.PathPrefix("/app").Handler(spa)
router.PathPrefix("/").Handler(spa)
So try like below. I tried your static folder with following:
package main
import (
"log"
"net/http"
"os"
"path/filepath"
"time"
"github.com/gorilla/mux"
)
type spaHandler struct {
staticPath string
indexPath string
}
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)
}
func main() {
router := mux.NewRouter()
spa := spaHandler{staticPath: "static", indexPath: "index.html"}
router.PathPrefix("/app").Handler(spa)
srv := &http.Server{
Handler: router,
Addr: ":3000",
// Good practice: enforce timeouts for servers you create!
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}
I am currently working on a Go web server utilizing the builtin templates.
The current issue I am having is that when I run the web server, it is serving the correct files but it does not load any media on the site.(Such as pictures and fonts) When I run the .html file as it is all media is loaded so I know it has something to do with my back end. Here is my code :
var templates = template.Must(template.ParseGlob("static/*.html"))
...
func index(w http.ResponseWriter, r *http.Request) {
currentTime := time.Now().Local()
toSend := payload{
Date: currentTime.Format("01-02-2006"),
Status: "Active",
}
t, err := template.ParseFiles("static/index.html")
if err != nil {
log.Fatalf("Error parsing template: %v", err)
}
t.Execute(w, toSend)
}
...
And here is my file path:
app
|-main.go
|-static(contains static files)
|-media(contains all media)
|-index.html
This serves the templates perfectly fine with all the required data yet without any media. All help is appreciated thank you!
Answered by #Adrian in the comments, I simply wasn't loading the media assets via the go server for the html to use.
http.Handle("/media/",http.StripPrefix("/media/",http.FileServer(http.Dir("static/media"))))
Was all I needed
I'm using gorilla serve mux to serve static html files.
r := mux.NewRouter()
r.PathPrefix("/").Handler(http.FileServer(http.Dir("./public"))).Methods("GET")
I do have a Index.html file inside the public folder as well as other html files.
When browsing the site I get all the content of the folder instead of the default Index.html.
I came from C# and I know that IIS takes Index.html as default but it is possible to select any page as a default.
I wanted to know if there's a proper way to select a default page to serve in Gorilla mux without creating a custom handler/wrapper.
Maybe using a custom http.HandlerFunc would be easier:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Here you can check if path is empty, you can render index.html
http.ServeFile(w, r, r.URL.Path)
})
You do have to make a custom handler because you want a custom behavior. Here, I just wrapped the http.FileServer handler.
Try this one:
package main
import (
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
handler := mux.NewRouter()
fs := http.FileServer(http.Dir("./public"))
handler.PathPrefix("/").Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
//your default page
r.URL.Path = "/my_default_page.html"
}
fs.ServeHTTP(w, r)
})).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", handler))
}
So, from the code, if the visited path is the root (/) then you rewrite the r.URL.Path to your default page, in this case my_default_page.html.
After grabthefish mentioned it i decided to check the actual code of gorilla serve mux.
This code is taken from net/http package which Gorilla mux is based on.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string,
redirect bool) {
const indexPage = "/index.html"
// redirect .../index.html to .../
// can't use Redirect() because that would make the path absolute,
// which would be a problem running under StripPrefix
if strings.HasSuffix(r.URL.Path, indexPage) {
localRedirect(w, r, "./")
return
}
the code request the index file to be index.html in lower case so renaming my index file solved it.
thank you grabthefish!
I've got this simple go lang webserver that does nothing more but parsing some data into an external HTML file and serve that file to the webserver.
package main
import (
"html/template"
"net/http"
)
type Event struct {
Name string
}
func handler(w http.ResponseWriter, r *http.Request) {
e := Event{ Name: "Melt! Festival" }
t, _ := template.ParseFiles("events.html")
t.Execute(w, e)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":1337", nil)
}
But whenever I try to parse the HTML file with the set it parses my html-page as text in stead of rendering the HTML in the browser
<!DOCTYPE>
<html>
<head>
<title>Event</title>
</head>
<body>
<p>
Event: {{.Name}}
</p>
</body>
</html>
When I leave the <!DOCTYPE> out of the HTML-file it renders it just fine.
Can anyone tell me why this is because I'm really curious? I spent two hours searching for the cause of my go code not working.
Your doctype declaration is incorrect, thus having an effect opposite from the desired one : it is probably interpreted by the browser as signifying the document isn't HTML.
Use this :
<!DOCTYPE html>
See reference.
Have you tried using DOCTYPE html in your file instead?
I wrote a very basic web application, following this tutorial. I want to add css rules in an external stylesheet, but it's not working - when the HTML templates are rendered, something goes wrong and the CSS is completely ignored. If I put the rules in tags, it works, but I don't want to have to deal with that.
In a Go web application, how do I render an external CSS stylesheet?
Add a handler to handle serving static files from a specified directory.
eg. create {server.go directory}/resources/ and use
http.Handle("/resources/", http.StripPrefix("/resources/", http.FileServer(http.Dir("resources"))))
along with /resources/somethingsomething.css
The reason for using StripPrefix is that you can change the served directory as you please, but keep the reference in HTML the same.
eg. to serve from /home/www/
http.Handle("/resources/", http.StripPrefix("/resources/", http.FileServer(http.Dir("/home/www/"))))
Note that this will leave the resources directory listing open.
If you want to prevent that, there is a good snippet on the go snippet blog:
http://gosnip.posterous.com/disable-directory-listing-with-httpfileserver
Edit: Posterous is now gone, so I just pulled the code off of the golang mailing list and will post it here.
type justFilesFilesystem struct {
fs http.FileSystem
}
func (fs justFilesFilesystem) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
if err != nil {
return nil, err
}
return neuteredReaddirFile{f}, nil
}
type neuteredReaddirFile struct {
http.File
}
func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
Original post discussing it: https://groups.google.com/forum/#!topic/golang-nuts/bStLPdIVM6w
And use it like this in place of the line above:
fs := justFilesFilesystem{http.Dir("resources/")}
http.Handle("/resources/", http.StripPrefix("/resources/", http.FileServer(fs)))