Skip to content

antony@notes:~/misc$ cat "撰寫-Go-CGI-程式.md"

撰寫 Go CGI 程式

2025-05-24· misc

撰寫 Go 靜態網站並啟動 CGI

實作目標

建立一個簡單的 Go 網頁伺服器,能夠提供靜態檔案服務,並透過 CGI(Common Gateway Interface)執行 Bash script。

章節

[TOC]

第一步:建立專案目錄並進入

mkdir ~/gocgi/; cd ~/gocgi/
  • mkdir ~/gocgi/:在使用者的家目錄下建立一個名為 gocgi 的資料夾。
  • cd ~/gocgi/:進入剛建立的 gocgi 資料夾。

目的:為專案建立一個獨立的工作目錄,便於管理相關的程式碼和資源。

第二步:撰寫 Go 程式碼並儲存為 main.go

echo 'package main

import (
  "net/http"
  "net/http/cgi"
)

func cgiDB(w http.ResponseWriter, r *http.Request) {
  handler := cgi.Handler{Path: "./www/cgi/cgidb.sh"}
  handler.ServeHTTP(w, r)
}

func cgiTBL(w http.ResponseWriter, r *http.Request) {
  handler := cgi.Handler{Path: "./www/cgi/cgitbl.sh"}
  handler.ServeHTTP(w, r)
}

func main() {
  static := http.FileServer(http.Dir("./www/"))
  http.Handle("/", static)

  http.HandleFunc("/db", cgiDB)
  http.HandleFunc("/tbl", cgiTBL)

  http.ListenAndServe(":8080", nil)
}' > main.go
  • 這段指令使用 echo 將多行的 Go 程式碼寫入 main.go 檔案。

程式碼解析

  • package main:定義此程式屬於 main 套件,表示這是一個可執行的程式。
  • import:引入標準庫中的 net/httpnet/http/cgi 套件,用於建立 HTTP 伺服器和處理 CGI。
  • cgiDBcgiTBL 函式:分別處理 /db/tbl 路徑的請求,執行對應的 Shell 腳本。
  • main 函式:
    • http.FileServer:提供 ./www/ 目錄下的靜態檔案服務。
    • http.Handlehttp.HandleFunc:設定路由,將特定的路徑對應到處理函式。
    • http.ListenAndServe(":8080", nil):啟動伺服器,監聽 8080 埠口。
  • 目的:建立一個基本的網頁伺服器,能夠提供靜態檔案服務,並透過 CGI 執行特定的 Shell 腳本。

第三步:初始化 Go 模組

go mod init gocgi
  • go mod init gocgi:初始化一個名為 gocgi 的 Go 模組,會在當前目錄下建立一個 go.mod 檔案。

目的:使用 Go Modules 管理專案的相依性,這是 Go 官方推薦的依賴管理方式。

第四步:編譯 Go 程式

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main
  • CGO_ENABLED=0:禁用 CGO,確保編譯出的二進位檔案是純 Go 程式,無需依賴 C 語言的函式庫。
  • GOOS=linux:設定目標作業系統為 Linux。
  • GOARCH=amd64:設定目標架構為 64 位元。
  • go build -o main:編譯 main.go,輸出為名為 main 的可執行檔案。

總結

整體流程如下:

  1. 建立並進入專案目錄。
  2. 撰寫並儲存 Go 程式碼,建立一個簡單的網頁伺服器。
  3. 初始化 Go 模組,管理相依性。
  4. 編譯程式,生成適用於 Linux 64 位元系統的可執行檔案。

程式介紹

package main

import (
  "net/http"
  "net/http/cgi"
)

func cgiDB(w http.ResponseWriter, r *http.Request) {
handler := cgi.Handler{Path: "./www/cgi/cgidb.sh"}
handler.ServeHTTP(w, r)
}

func cgiTBL(w http.ResponseWriter, r *http.Request) {
handler := cgi.Handler{Path: "./www/cgi/cgitbl.sh"}
handler.ServeHTTP(w, r)
}

func main() {
  static := http.FileServer(http.Dir("./www/"))
  http.Handle("/",static)

  http.HandleFunc("/db", cgiDB)
  http.HandleFunc("/tbl", cgiTBL)

  http.ListenAndServe(":8080", nil)
}

這段 Go 程式碼建立了一個簡單的 HTTP 伺服器,具備以下功能:

  1. 提供靜態檔案服務:透過 http.FileServer,伺服器會從 ./www/ 目錄提供靜態檔案,如 HTML、CSS、JavaScript 等。
  2. 處理 CGI 請求:對於特定路徑(/db/tbl),伺服器會執行對應的 CGI 腳本(cgidb.shcgitbl.sh),並將其輸出作為 HTTP 回應返回給用戶端。

📁 靜態檔案服務

static := http.FileServer(http.Dir("./www/"))
http.Handle("/", static)
  • http.FileServer 建立一個處理器,用於提供指定目錄中的靜態檔案。
  • http.Dir("./www/") 指定了靜態檔案的根目錄。
  • http.Handle("/", static) 將根路徑 / 的請求導向這個處理器。

效果:當用戶端請求 http://localhost:8080/index.html 時,伺服器會返回 ./www/index.html 檔案的內容。


⚙️ CGI 處理器

func cgiDB(w http.ResponseWriter, r *http.Request) {
    handler := cgi.Handler{Path: "./www/cgi/cgidb.sh"}
    handler.ServeHTTP(w, r)
}

func cgiTBL(w http.ResponseWriter, r *http.Request) {
    handler := cgi.Handler{Path: "./www/cgi/cgitbl.sh"}
    handler.ServeHTTP(w, r)
}
  • 這兩個函式分別處理 /db/tbl 路徑的請求。
  • cgi.Handler 是 Go 標準庫 net/http/cgi 提供的類型,用於執行 CGI 腳本。
  • Path 指定了要執行的 CGI 腳本路徑。
  • ServeHTTP 方法會執行指定的 CGI 腳本,並將其輸出作為 HTTP 回應返回給用戶端。

效果:當用戶端請求 http://localhost:8080/db 時,伺服器會執行 ./www/cgi/cgidb.sh 腳本,並將其輸出返回給用戶端。


🚀 主函式

func main() {
    static := http.FileServer(http.Dir("./www/"))
    http.Handle("/", static)

    http.HandleFunc("/db", cgiDB)
    http.HandleFunc("/tbl", cgiTBL)

    http.ListenAndServe(":8080", nil)
}
  • 設定靜態檔案服務處理器。
  • 註冊 /db/tbl 路徑的處理函式。
  • 啟動 HTTP 伺服器,監聽本地端口 8080。

📌 總結

這段 Go 程式碼建立了一個基本的 HTTP 伺服器,能夠提供靜態檔案服務,並透過 CGI 腳本處理特定路徑的請求。這種架構適合用於簡單的網站或內部工具,但在實際部署時,仍需考慮安全性和錯誤處理等因素。