I wrote code in golango to connect to the database on the server and output the contents of the tables to the website. I also wrote code for the html output of the table. There are no problems and it connects, but the error "404 page not found" lights up on the web page. What is this error and what is the reason? This is the first time I've seen this
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"html/template"
_ "log"
"net/http"
)
type Жанр struct {
idЖанр int
Название_жанра string
}
var database *sql.DB
func home_db(w http.ResponseWriter, r *http.Request) {
rows, err := database.Query("select * from newbd.Жанр")
if err != nil {
panic(err)
}
defer rows.Close()
ganr := []Жанр{}
for rows.Next() {
p := Жанр{}
err = rows.Scan(&p.idЖанр, &p.Название_жанра)
if err != nil {
panic(err)
continue
}
ganr = append(ganr, p)
}
tmpl, _ := template.ParseFiles("home.html")
tmpl.Execute(w, ganr)
}
func main() {
db, err := sql.Open("mysql", "xxxxx:xxxxxx#tcp(xx.xx.xxx.xxx:xx)/xxxxx")
if err != nil {
panic(err)
}
defer db.Close()
fmt.Println("OK")
http.HandleFunc("/dat/", home_db)
http.ListenAndServe(":8100", nil)
}
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RUMP</title>
</head>
<body>
<table>
<thead>
<th>idЖанр</th>
<th>Название_жанра</th>
</thead>
{{range . }}
<li>
<td>{{.idЖанр}}</td>
<td>{{.Название_жанра}}</td>
</li>
{{.end}}
</table>
</body>
</html>
I am building a website using Golang templates and needed to display some text in the footer template. It's a variable that resolves in header.html and index.html.
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
type Data struct {
Title string
Field1 string
Field2 template.HTML
FooterField string
}
var tmpl *template.Template
func main() {
router := mux.NewRouter()
port := ":8085"
data := Data{}
data.Title = "Title"
data.FooterField = "This text does not appear in the footer template"
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, "index", data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
var err error
tmpl, err = template.ParseGlob("views/*")
if err != nil {
panic(err.Error())
}
router.PathPrefix("/").HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir("./static/")).ServeHTTP(res, req)
})
fmt.Println("Server running on localhost" + port)
err = http.ListenAndServe(port, handlers.CompressHandler(router))
if err != nil {
log.Fatal(err)
}
}
And in the ./views I have header.html
{{define "header"}}<!doctype html><html lang="en"><head><meta charset="utf-8"><title>{{.Title}}</title></head><body><h1>Header template</h1><div>{{.FooterField}}</div>{{end}}
index.html
{{define "index"}}{{template "header" . }}
<h1>Index template</h1>
<div>{{.FooterField}}</div>
{{template "footer"}}{{end}}
footer.html
{{define "footer"}}<h1>Footer template</h1>
Missing FooterField->{{.FooterField}}</body></html>{{end}}
And finally the output in the browser on http://localhost:8085/
Header template
This text does not appear in the footer template
Index template
This text does not appear in the footer template
Footer template
Missing FooterField->
This code should be able to be reproduced simply by copying and pasting.
Any clue to what my issue is?
you are not passing anything to the footer template. But you pass . to the header template, so you see the value of .FooterField only there.
In index.html change it to: {{template "footer" . }}
Guys I am making a create your own adventure type book in which the user has options to select events. I am taking the story data from a json file. I have created two files named story.go and main.go where story.go handles all the functions and main.go has only the server. Look at the following codes
story.go
package gyg
import (
"encoding/json"
"io"
"net/http"
"text/template"
)
var defaultHandlerTemplate = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Give Yourself Goosebumps</title>
</head>
<body>
<h1>{{.Title}}</h1>
{{range .Paragraphs}}
<p>{{.}}</p>
{{end}}
<ul>
{{range .Options}}
<li> {{.Text}} </li>
{{end}}
</ul>
</body>
</html>
`
var tpl *template.Template
type Story map[string]Chapter
type Chapter struct {
Title string `json:"title"`
Paragraphs []string `json:"story"`
Options []Option `json:"options"`
}
type Option struct {
Text string `json:"text"`
Arc string `json:"arc"`
}
type handler struct {
s Story
}
func init() {
tpl = template.Must(template.New("").Parse("defaultHandlerTemplate"))
}
func JsonStory(r io.Reader) (Story, error) {
d := json.NewDecoder(r)
var story Story
if err := d.Decode(&story); err != nil {
return nil, err
}
return story, nil
}
func NewHandler(s Story) http.Handler {
return handler{s}
}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := tpl.Execute(w, h.s["intro"])
if err != nil {
panic(err)
}
}
main.go
package main
import (
"flag"
"fmt"
"go-projects/gyg"
"log"
"net/http"
"os"
)
func main() {
filename := flag.String("file", "gopher.json", "the file with GYG story.")
flag.Parse()
f, err := os.Open(*filename)
if err != nil {
panic(err)
}
story, err := gyg.JsonStory(f)
if err != nil {
panic(err)
}
server := http.Server{
Addr: "127.0.0.1:3000",
}
h := gyg.NewHandler(story)
fmt.Printf("Startin the server on port %s\n", server.Addr)
log.Fatal(http.ListenAndServe(server.Addr, h))
}
On running main.go the server is listening on port 3000 but when opening port 3000 on browser, it's displaying
defaultHandlerTemplate
I am trying to include CSS and JS files in my html templates using Go.
Here is my code
main.go
package main
import (
"fmt"
"net/http"
)
func main() {
var mux = http.NewServeMux()
registerRoutes(mux)
httpServer := http.Server{
Addr: ":3000",
Handler: mux,
}
err := httpServer.ListenAndServe()
if err != nil {
fmt.Print(err)
}
}
routes.go
package main
import "net/http"
func registerRoutes(mux *http.ServeMux) {
mux.HandleFunc("/", index)
mux.HandleFunc("/faq", faq)
}
handlers.go
package main
import (
"fmt"
"html/template"
"net/http"
)
func index(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("templates/index.html")
if err != nil {
fmt.Print(err)
}
err = tmpl.Execute(w, nil)
if err != nil {
fmt.Print(err)
}
}
func faq(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("templates/faq.html")
if err != nil {
fmt.Print(err)
}
err = tmpl.Execute(w, nil)
if err != nil {
fmt.Print(err)
}
}
index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Index</title>
<link href="../static/stylesheets/main.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="../static/scripts/index.js"></script>
</head>
<body>
<h1>Test</h1>
</body>
</html>
Rendering the HTML works, but it does not include the CSS or JS files. How can I get it to recognise them?
Thanks.
EDIT: As suggested by #Burak Serdar, I have implemented the following code:
Added this to handlers.go
func staticHandler(w http.ResponseWriter, r *http.Request) {
// load the file using r.URL.Path, like /static/scripts/index.js"
path := r.URL.Path
data, err := ioutil.ReadFile(path)
if err != nil {
fmt.Print(err)
}
if strings.HasSuffix(path, "js") {
w.Header().Set("Content-Type","text/javascript")
} else {
w.Header().Set("Content-Type","text/css")
}
_, err = w.Write(data)
if err != nil {
fmt.Print(err)
}
}
Added this to routes.go
mux.HandleFunc("/static", staticHandler)
However, it still does not work.
Perhaps I should note that static/ and templates/ are in the same folder, and these share the folder with main.go etc.
EDIT2: It seems like my method may not be the best, and so I am trying to use the inbuilt FileServer. However, I can't quite work out how to do it.
I added this line
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("C:/Users/x/Documents/Coding/Go/hello_world/"))))
to registerRoutes but it's not working.
EDIT3: Perhaps I should make it clear what I am trying to achieve. I am attempting to reach Flask-like functionality in Go. This means redirecting to certain templates based on the path visited. What I mean by a template is a .html file that I can pass variables to.
EDIT4: I think I have achieved what I wanted. I added
fs := http.FileServer(http.Dir("static"))
mux.Handle("/static/", http.StripPrefix("/static", fs))
to my main() function in main.go. Then removed mux.HandleFunc("/static/", staticHandler) and the staticHandler function.
EDIT5: Assuming that is a good method, my last concern is how to handle caching. It is clear that I am parsing the files every time the page is rendered with tmpl, err := template.ParseFiles("templates/index.html") etc. As such, I thought perhaps I could add a function to load these files and return the templates, then call this function in main and pass the variables to the handlers. Is this a good idea? How would you go about doing it exactly? Does this mean my files only get updated when I restart my web server?
For example
func initTemplates() (*template.Template, *template.Template) {
indexTemplate := template.Must(template.ParseFiles("templates/index.html"))
faqTemplate := template.Must(template.ParseFiles("templates/faq.html"))
return indexTemplate, faqTemplate
}
func main() {
var mux = http.NewServeMux()
fs := http.FileServer(http.Dir("static"))
mux.Handle("/static/", http.StripPrefix("/static", fs))
indexTemplate, faqTemplate := initTemplates()
...
}
My problem with this is it seems strange to have a variable here like this for each page on my website. What if I want to have 100 pages? Additionally, how do I even pass these variables to my handling functions defined above?
EDIT6:
How about this?
main.go
var templates map[string]*template.Template
func init() {
if templates == nil {
templates = make(map[string]*template.Template)
}
templates["index.html"] = template.Must(template.ParseFiles("templates/index.html"))
templates["faq.html"] = template.Must(template.ParseFiles("templates/faq.html"))
}
func main() {
var mux = http.NewServeMux()
fs := http.FileServer(http.Dir("static"))
mux.Handle("/static/", http.StripPrefix("/static", fs))
registerRoutes(mux)
httpServer := http.Server{
Addr: ":3000",
Handler: mux,
}
err := httpServer.ListenAndServe()
if err != nil {
fmt.Print(err)
}
}
Then in handlers.go I use tmpl := templates["index.html"]
EDIT7: Not sure if I should make a new question at this point but I'll just keep going.
I ran into a problem when trying to service the resource /purchase/license. Now the server is looking in /purchase/static/stylesheets/main.css on that page. How can I resolve this?
EDIT8: I resolved my previous edit by adding
mux.Handle("/purchase/static/", http.StripPrefix("/purchase/static", fs))
to main(). Is there a better, more scaleable way of resolving this? What if I have hundreds of /x/y, do I really need to add one of these for each x? Could I use regex or something to add a wildcard like this?
mux.Handle("*/static/", http.StripPrefix("*/static", fs))
If so, how would I do that exactly?
You have to "serve" the JS and CSS files as well.
The template is rendered and sent as an HTML page. Once the HTML page is loaded, the browser tries to load the CSS and JS files using the links in the page. Since your server does not handle those routes, the browser cannot load them.
I suggest instead of using ../static path, use /static in the HTML, and mount that route to your router with a handler that loads the CSS and JS files and returns them. You also have to set the Content-Type of the response so the browser can use those files correctly.
// Register the handler
mux.HandleFunc("/static", staticHandler)
func staticHandler(w http.ResponseWriter, r *http.Request) {
// load the file using r.URL.Path, like /static/scripts/index.js"
data,err:=ioutil.ReadFile(...)
// Figure out file type:
if strings.EndsWith("js") {
w.Header.Set("Content-Type","text/javascript")
} else {
w.Header.Set("Content-Type","text/css")
}
w.Write(data)
}
Thanks to #Burak Serdar for the guidance, I fixed some of his code and added a few things to get a solution.
Added this to handlers.go
func staticHandler(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if strings.HasSuffix(path, "js") {
w.Header().Set("Content-Type","text/javascript")
} else {
w.Header().Set("Content-Type","text/css")
}
data, err := ioutil.ReadFile(path[1:])
if err != nil {
fmt.Print(err)
}
_, err = w.Write(data)
if err != nil {
fmt.Print(err)
}
}
Added this to routes.go
mux.HandleFunc("/static/", staticHandler)
I have a simple main.go script that loads a template from a folder. The template looks like:
<html>
<head>
<title>T2 template</title>
</head>
<body>
hello
</body>
</html>
The main.go script looks is:
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"os"
"github.com/gorilla/mux"
)
var (
templates = template.Must(template.ParseFiles("templates/index.html"))
)
func main() {
port := os.Getenv("PORT")
fmt.Printf("port is: %v\n", port)
r := mux.NewRouter()
r.HandleFunc("/hello", HomeHandler)
log.Fatal(http.ListenAndServe(":"+port, r))
}
func HomeHandler(w http.ResponseWriter, r *http.Request) {
tmpl := "templates/index.html"
err := templates.ExecuteTemplate(w, tmpl, "")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
I'm not sure what is wrong here.
The error I see in the browser is:
"templates/index.html" is undefined
The ParseFiles doc says:
The returned template's name will have the (base) name and (parsed) contents of the first file.
To execute the template, use the base name of "templates/index.html":
tmpl := "index.html"
err := templates.ExecuteTemplate(w, tmpl, "")