I can't figure out this error in go lang when executing a template
panic: open templates/*.html: The system cannot find the path specified.
another problem is that my public folder can't be served from css and I don't know why.
code:
package main
import (
"net/http"
"github.com/gorilla/mux"
"html/template"
"log"
)
var tpl *template.Template
func init() {
tpl = template.Must(template.ParseGlob("templates/*.html"))
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/",home)
http.Handle("/public/", http.StripPrefix("/public/",
http.FileServer(http.Dir("/pub"))))
http.ListenAndServe(":8080", r)
}
func home(writer http.ResponseWriter, request *http.Request) {
err := tpl.ExecuteTemplate(writer, "index.html", nil)
if err != nil {
log.Println(err)
http.Error(writer, "Internal server error", http.StatusInternalServerError)
}
}
my folder is like that:
bin pkg pub css home.css js src github.com gorila/mux templates index.html
my GOROOT is pointing to the folder project
which contains the bin
pkg
src
when I make the templates
folder outside src
it works fine but I thinks that's not right everything must be in src
right ?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<link href="../public/css/home.css" type="text/css" rel="stylesheet" />
</head>
<body>
<h1>welcome! hi</h1>
</body>
</html>
here i can't serve the css
UPDATE::
the first problem is solved of the templates folder .
but I am still cannot solve the second issue
I personally find the standard http
library very good and simple for such tasks. However, if you insist on Gorilla's mux
here is the problem I found in your code:
func main() {
...
http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("/pub"))))
http.ListenAndServe(":8080", r)
}
On one hand you are using http.Handle
to serve static files but on the other hand you're giving r
to http.ListenAndServe
.
To fix this just change that line into:
r.PathPrefix("/public/").Handler(
http.StripPrefix("/public/",
http.FileServer(http.Dir("/pub/"))))
If I may, I would like to suggest using flag
to set a different path to the templates directory and to the public directory so it would be easy to deploy and run your server.
In other words, instead of hardcoding the path to these directories you can run:
./myserver -templates=/loca/templates -public=/home/root/public
To do that just add the following:
import "flag"
....
func main() {
var tpl *template.Template
var templatesPath, publicPath string
flag.StringVar(&templatesPath, "templates", "./templates", "Path to templates")
flag.StringVar(&publicPath, "public", "./public", "Path to public")
flag.Parse()
tpl = template.Must(template.ParseGlob(templatesPath+"/*.html"))
r.HandleFunc("/", handlerHomeTemplates(tpl))
r.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir(publicPath))))
...
}
func handlerHomeTemplates(tpl *template.Template) http.HandlerFunc {
return http.HandlerFunc(func((writer http.ResponseWriter, request *http.Request) {
err := tpl.ExecuteTemplate(writer, "index.html", nil)
if err != nil {
...
}
})
}
Even thought the init
function is a good place to do part of it, I think it's a good practice to avoid it unless it's needed. That's why I did all the initialization in the main
function and used handlerHomeTemplates
to return a new http.HandleFunc
that uses templatesPath
.