位元詩人 [Golang] 網頁設計教學:製作靜態網頁

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

我們先前的範例皆回傳純文字頁面,但實務上我們會回傳 HTML 頁面給使用者觀看,或是回傳 XML (或 JSON) 文件來傳輸資料。本文說明在網頁程式中加入 HTML 頁面的方式。

(反模式) 直接嵌入網頁

HTML 文件在本質上是加了標籤 (tag) 的文字文件,所以我們可以直接把整個 HTML 文件當成是一個多行字串輸出。按照這個想法寫出以下 (不良的) 程式碼:

package main

import (
    "github.com/julienschmidt/httprouter"
    "net/http"
)

func main() {
    mux := httprouter.New()
    mux.GET("/", index)

    server := http.Server{
        Addr: "127.0.0.1:8080",
        Handler: mux,
    }

    server.ListenAndServe()
}

func index(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
    // NEVER DO THIS IN PRODUCTION CODE
    str := `<!DOCTYPE html>
<html>
<head><title>Hello, HTML</title></head>
<body><h1>Hello, HTML</h1><p>Add more text here</p></body>
</html>
`
    w.Write([]byte(str))
}

實務上,我們當然不會這樣做。早期的 CGI 基本上就是用這個思維在寫程式,這套模式已經算是時代的眼淚,我們不需要重覆這樣的舊路線。

使用模板 (Template)

在實務上,我們會利用模板 (template) 將內容和版面進行初步的分離。模板是網頁的骨架,會預先寫好一些和板面相關的代碼,要使用模板時再填入原本尚未完成的內容即可。透過模板引擎 (template engine) 的處理,模板和填入的資料會合併後轉為頁面。理論上所有文字格式的內容都能透過這種模式輸出。

在 Golang 網頁程式中,我們通常拿模板來輸出 HTML 頁面。XML 和 JSON 文件則會用相關函式庫來産生,不會直接用模板去生 XML 或 JSON 文件。

以本例來說,我們在 views/index.html 加入以下模板:

<!DOCTYPE html>
<html>
<head>
    <title>{{ . }}</title>
</head>
<body>
    <p>{{ . }}</p>
</body>
</html>

在此模板中,{{ . }} 部分即是挖空的內容,我們可以依需求填入不同的內容。

接著來看主程式的部分:

package main

import (
    "github.com/julienschmidt/httprouter"
    "html/template"
    "net/http"
)

func main() {
    mux := httprouter.New()
    mux.GET("/", index)

    server := http.Server{
        Addr: "127.0.0.1:8080",
        Handler: mux,
    }

    server.ListenAndServe()
}

func index(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
    t := template.Must(template.ParseFiles("views/index.html"))

    t.Execute(w, "Hello, Template")
}

本程式的關鍵在於建立和使用模板,我們稍微說明一下。如果想查 API 的使用方式,請查閱 http/template 的文件。

使用 template.Must 可以建立模板,其函式原型如下:

func template.Must(tmpl, error) *tmpl

但我們的範例是這樣:

template.Must(template.ParseFiles("views/index.html"))

如果看範例,會以為我們只傳入一個參數。但實際上我們傳入兩個參數,因為 template.ParseFiles 即會回傳兩個參數,所以可以滿足 template.Must 的 API。會有這樣的現象是因為 template.Must 是設計來搭配其他函式,以簡化建立模板的過程。

接著來看以 Execute 函式生成模板的函式原型:

func tmpl.Execute(out, data) err

out 是輸出的目標,在本範例是 http.ResponseWriterdata 利用空介面的特性,可視需求傳入不同的東西。理論上要檢查是否引發錯誤,但本範例為了簡化程式碼,省略這個步驟。

結語

在本文中,我們以簡短的範例來展示如何在 Golang 網頁程式中使用模板。在後續的文章中,我們會介紹 Golang 的模板的語法。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。