位元詩人 [Golang] 網頁設計教學:撰寫第一個程式

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

在本文中,我們透過極簡的 Hello World 程式來熟悉如何用 Go 撰寫網頁程式。根據網頁是否要加密,程式的寫法略有不同,讀者可相互比較一下。

一般版的 Hello World

所謂的一般版是指透過未加密的 HTTP 協定傳輸的網頁程式。透過未加密的 HTTP 協定來傳輸頁面和資料時,不需要做額外的配置,過程較簡單;日後網站要上線時,再將其轉為有加密的 HTTPS 協定即可。

範例程式碼如下:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    // Listen to the root path of the web app
    http.HandleFunc("/", handler)

    // Start a web server.
    http.ListenAndServe(":8080", nil)
}

// The handler for the root path.
func handler(writer http.ResponseWriter, request *http.Request) {
    fmt.Fprintf(writer, "Hello, World")
}

在 Go 語言中,撰寫網頁後端程式的主要套件是 net/http。我們會陸續撰寫一些範例,建議讀者搭配該套件的 API 文件來學習,不要直接死記本系列文章中範例的寫法。

http.HandleFunc 的目的是登記網站路徑的處理器,其函式原型如下:

http.HandleFunc(path, handler)

以本例 http.HandleFunc("/", handler) 來說,我們在根目錄 / 中登記 handler 這個處理器,網站使用者在向該路徑發出請求 (request) 時,我們的程式即會使用 handler 所實做的內容來回應 (reponse)。在語法上來說,handler 是一個函式,我們這個程式把 handler 當成參數傳入 http 物件中,用到函數式程式的寫法。

http.ListenAndServe 會啟動一個網頁伺服程式,其函式原型如下:

http.ListenAndServe(addr, handler)

addr 是用來表示網址的字串,handler 則傳入 ServeMux。所謂的 ServeMux 是 HTTP request multiplexer (mux),mux 統籌處理該網頁程式有登記的路徑及其處理器 (handler),將傳入的路徑指向相對應的處理器,也就是整個網頁程式的路由 (router)。在本例中我們傳入 nil,代表使用內建的 DefaultServeMux

註:本文的處理器 (handler) 是指處理特定的 HTTP 請求 (request) 的程式碼區塊 (函式或物件),不要和電腦的中央處理器 (CPU) 搞混。

處理器 (handler) 的寫法如下:

func handler(w http.ResponseWriter, req *http.Request) {
    // Write something here.
}

處理器以 *http.Requesthttp.ResponseWriter 為參數,該參數分別代表網頁的請求 (request) 和回應 (response)。以本例來說,我們忽略請求的部分,直接把 "Hello World" 字串輸出到回應。

使用 Go 主程式執行該程式即可:

$ go run main.go

(選擇性) 加密版的 Hello World

在先前的版本中,我們的程式是走未加密的 HTTP 協定,一般情形下是夠用了;必要時,我們仍然可走有加密的 HTTPS 協定。本節說明如何建立走 HTTPS 的 Hello World 程式。

我們要先安裝 OpenSSL,在類 Unix 系統上使用系統提供的套件即可,若在 Windows 上,可透過 Chocolatey 安裝該套件。利用 OpenSSL 的終端機工具輸入以下指令產生認證和金鑰:

$ openssl req -newkey rsa:4096 -nodes -sha512 -x509 -days 3650 -nodes -out cert.pem -keyout key.pem

透過此指令,會產生 cert.pemkey.pem,待會會用到。

撰寫主程式的部分:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", handler)

    // Start a secure (but not trusted) web server.
    http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil)
}

func handler(writer http.ResponseWriter, request *http.Request) {
    fmt.Fprintf(writer, "Hello, World")
}

可以看得出來程式碼和先前差不多,主要是啟動時的函式換成 http.ListenAndServeTLS。該函式的原型如下:

http.ListenAndServeTLS(addr, cert, key, handler)

addr 和先前一樣,填入網址。certkey 分別是認證和金鑰的路徑,按照實際情形填入即可。handler 和先前一樣,是 ServeMux,填入 nil 代表使用預設的 mux。

使用 https://localhost:8080/ 就可以連到該站台,但使用較新的瀏覽器連線到該站台時,會發現瀏覽器警告我們該站台不安全。這是因為我們的認證和金鑰沒有經過第三方機構公證。由於在早期網站只是要內部使用,直接忽視該警告訊息即可,不用一開始就去進行公證。

現在有新的工具可以產生受信任的認證和金鑰,有需要的讀者可看下一節。

(選擇性) 製作受信賴的憑證

我們上一節談的方法是開發早期需走 HTTPS 時所用的一般性方法,其實應該夠用了。不過,透過 mkcert 這套工具,我們可以不需額外的設定,直接產生受信任的認證和金鑰,簡化開發時程。

輸入以下指令以產生憑證:

$ mkcert -install

接著,輸入以下指令以產生適用於 localhost127.0.0.1 的認證和金鑰:

$ mkcert localhost 127.0.0.1
Using the local CA at "C:\Users\cwchen\AppData\Local\mkcert" ✨

Created a new certificate valid for the following names 📜
 - "localhost"
 - "127.0.0.1"

The certificate is at "./localhost+1.pem" and the key at "./localhost+1-key.pem" ✅

在啟動伺服器時指定上述檔案即可:

// Start a secure and trusted web server.
http.ListenAndServeTLS("localhost:8080", "localhost+1.pem", "localhost+1-key.pem", nil)

連到該站台時,會發現瀏覽器不再吐警告訊息了。

要注意這個軟體憑證只適用於開發階段,不能用在真正要上線的網頁程式,會有安全上的問題。我們會在發布程式 (deployment) 的章節中,說明如何使用 Let's Encrypt 來産生可用在實際上線的環境的憑證。

結語

雖然這個網頁程式很簡單,但這是了解 Golang 網頁程式的第一步,請讀者還是要實際練習一下。

在撰寫網頁程式的初期,先用無加密的網頁程式其實無妨;但程式要上線前,最好還是改成加密的版本。現在 HTTPS 可說是網站和網頁程式的標配,不應該再把沒加密的網頁程式直接上線。

關於作者

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

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