Dnes si vytvoríme jednoduchý webserver statických stránok so šablónami
Go webserver so šablónami
Go obsahuje balíček html/template
, ktorý implementuje prácu so šablonami pre generovanie HTML na základe šablony a dynamických dát. Šablony sú zabezpečené proti vložení a spustení kódu, predpokladajú, že tvorca šablon je dôveryhodný, ale ale kto ju spúšťa s dátami tak nie, preto použité dynamické dáta budú sanitizované a escapované špecifické znaky pre HTML, CSS, JavaScript a URI.
Podstránky
- / vráti stránku vyskladanú z layout.html + index.html
- /hello.html vráti stránku vyskladanú z layout.html + hello.html
- /static/… vráti statický súbor so správnym content-type
Adresárová štruktúra:
1
2
3
4
5
6
7
8
9
|
$ ls -R
.:
main.go static/ templates/
./static:
main.css
./templates:
hello.html index.html layout.html
|
Statické súbory
Najskôr si vytvoríme statické súbory:
/static/main.css
/templates/layout.html
Aby sme nemuseli pre každú stránku kopírovať všetok spoločný obsah, použijeme podporu šablón z balíčka Go template.
Layout súbor bude obsahovať spoločné prvky pre všetky stránky a jeho názov bude “layout”:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{{define "layout"}}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{{template "title"}}</title>
<link rel="stylesheet" href="/static/main.css">
</head>
<body>
<a href="/">Home</a> | <a href="/hello.html">Hello</a>
{{template "body"}}
<footer>created by Go templates at {{.}}</footer>
</body>
</html>
{{end}}
|
/templates/index.html
Index.html sa zobrazí buď keď priamo zavoláme /index.html alebo /.
1
2
3
4
|
{{define "title"}}Index{{end}}
{{define "body"}}
<h1>This is index page</h1>
{{end}}
|
/templates/hello.html
1
2
3
4
|
{{define "title"}}Template page{{end}}
{{define "body"}}
<h1>Hello from the other world</h1>
{{end}}
|
Main
Http balíček obsahuje funkciu FileServer, tá vracia handler, ktorý obsluhuje HTTP request vrátením statického súboru z určenej podadresárovej štruktúry. Tento handler nastavíme na obsluhu cesty /static. Ostatné HTTP requesty bude obsluhovať funkcia serveTemplate, ktorú si definujeme nižšie.
1
2
3
4
5
6
7
8
9
10
11
|
func main() {
fs := http.FileServer(http.Dir("./static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.HandleFunc("/", serveTemplate)
log.Println("Listening on :8000...")
err := http.ListenAndServe(":8000", nil)
if err != nil {
log.Fatal(err)
}
}
|
serveTemplate handler
Riadky:
- 2-3: vytvoria premenné s cestou na layout a volaný súbor
- 6: os.Stat vracia FileInfo štruktúru popisujúcu súbor alebo chybu ak neexistuje
- 7-10: ak súbor existuje ale je to adresár, tak prepíše volanie na index.html z daného adresára
- 13-18: ak súbor neexistuje vráti 404
- 20-27: vytvorí Template objekt zo šablón alebo vráti chybu 500
- 29-33: na výstup vyrenderuje šablónu “layout” a doplní aktuálny čas a dátum, v prípade chyby vráti 500
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
func serveTemplate(w http.ResponseWriter, r *http.Request) {
lp := filepath.Join("templates", "layout.html")
fp := filepath.Join("templates", filepath.Clean(r.URL.Path))
// Return the index page if the request is for a directory
info, err := os.Stat(fp)
if err == nil && info.IsDir() {
fp = filepath.Join("templates", filepath.Clean(r.URL.Path+"/index.html"))
info, err = os.Stat(fp)
}
// Return a 404 if the template doesn't exist
if err != nil {
if os.IsNotExist(err) {
http.NotFound(w, r)
return
}
}
tmpl, err := template.ParseFiles(lp, fp)
if err != nil {
// Log the detailed error
log.Println(err.Error())
// Return a generic "Internal Server Error" message
http.Error(w, http.StatusText(500), 500)
return
}
err = tmpl.ExecuteTemplate(w, "layout", time.Now().Format("2006.01.02 15:04:05"))
if err != nil {
log.Println(err.Error())
http.Error(w, http.StatusText(500), 500)
}
}
|
Celý zdrojový kód
Zdrojový kód môžete uložiť do súboru “main.go” a spustiť príkazom “go run main.go”, následne v prehliadači otvoriť http://localhost:8000:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
package main
import (
"html/template"
"log"
"net/http"
"os"
"path/filepath"
"time"
)
func main() {
fs := http.FileServer(http.Dir("./static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.HandleFunc("/", serveTemplate)
log.Println("Listening on :8000...")
err := http.ListenAndServe(":8000", nil)
if err != nil {
log.Fatal(err)
}
}
func serveTemplate(w http.ResponseWriter, r *http.Request) {
lp := filepath.Join("templates", "layout.html")
fp := filepath.Join("templates", filepath.Clean(r.URL.Path))
// Return the index page if the request is for a directory
info, err := os.Stat(fp)
if err == nil && info.IsDir() {
fp = filepath.Join("templates", filepath.Clean(r.URL.Path+"/index.html"))
info, err = os.Stat(fp)
}
// Return a 404 if the template doesn't exist
if err != nil {
if os.IsNotExist(err) {
http.NotFound(w, r)
return
}
}
tmpl, err := template.ParseFiles(lp, fp)
if err != nil {
// Log the detailed error
log.Println(err.Error())
// Return a generic "Internal Server Error" message
http.Error(w, http.StatusText(500), 500)
return
}
err = tmpl.ExecuteTemplate(w, "layout", time.Now().Format("2006.01.02 15:04:05"))
if err != nil {
log.Println(err.Error())
http.Error(w, http.StatusText(500), 500)
}
}
|
Referencie
Vaše otázky, návrhy a komentáre
Verím, že vás tento návod inšpiroval a budem vďačný ak dáte spätnú väzbu a pomôže mi zamerať sa na to čo by vás zaujímalo.