使用 Golang 打造 Web 應用程式
  • Introduction
  • Go 環境配置
    • Go 安裝
    • GOPATH 與工作空間
    • Go 命令
    • Go 開發工具
    • 小結
  • Go 語言基礎
    • 你好,Go
    • Go 基礎
    • 流程和函式
    • struct
    • 物件導向
    • interface
    • 併發
    • 小結
  • Web 基礎
    • web 工作方式
    • Go 建立一個簡單的 web 服務
    • Go 如何使得 web 工作
    • Go 的 http 套件詳解
    • 小結
  • 表單
    • 處理表單的輸入
    • 驗證表單的輸入
    • 預防跨站指令碼
    • 防止多次提交表單
    • 處理檔案上傳
    • 小結
  • 存取資料庫
    • database/sql 介面
    • 使用 MySQL 資料庫
    • 使用 SQLite 資料庫
    • 使用 PostgreSQL 資料庫
    • 使用 beedb 函式庫進行 ORM 開發
    • NoSQL 資料庫操作
    • 小結
  • session 和資料儲存
    • session 和 cookie
    • Go 如何使用 session
    • session 儲存
    • 預防 session 劫持
    • 小結
  • 文字檔案處理
    • XML 處理
    • JSON 處理
    • 正則處理
    • 範本處理
    • 檔案操作
    • 字串處理
    • 小結
  • Web 服務
    • Socket 程式設計
    • WebSocket
    • REST
    • RPC
    • 小結
  • 安全與加密
    • 預防 CSRF 攻擊
    • 確保輸入過濾
    • 避免 XSS 攻擊
    • 避免 SQL 注入
    • 儲存密碼
    • 加密和解密資料
    • 小結
  • 國際化和本地化
    • 設定預設地區
    • 本地化資源
    • 國際化站點
    • 小結
  • 錯誤處理,除錯和測試
    • 錯誤處理
    • 使用 GDB 除錯
    • Go 怎麼寫測試案例
    • 小結
  • 部署與維護
    • 應用日誌
    • 網站錯誤處理
    • 應用部署
    • 備份和還原
    • 小結
  • 如何設計一個 Web 框架
    • 專案規劃
    • 自訂路由器設計
    • controller 設計
    • 日誌和配置設計
    • 實現部落格的增刪改
    • 小結
  • 擴充套件 Web 框架
    • 靜態檔案支援
    • Session 支援
    • 表單支援
    • 使用者認證
    • 多語言支援
    • pprof 支援
    • 小結
  • 參考資料
Powered by GitBook
On this page

Was this helpful?

  1. 表單

處理表單的輸入

先來看一個表單提交的例子,我們有如下的表單內容,命名成檔案 login.gtpl(放入當前建立專案的目錄裡面)

<html>
<head>
<title></title>
</head>
<body>
<form action="/login" method="post">
    使用者名稱:<input type="text" name="username">
    密碼:<input type="password" name="password">
    <input type="submit" value="登入">
</form>
</body>
</html>

上面提交表單到伺服器的/login,當用戶輸入資訊點選登入之後,會跳轉到伺服器的路由 login 裡面,我們首先要判斷這個是什麼方式傳遞過來,POST 還是 GET 呢?

http 套件裡面有一個很簡單的方式就可以取得,我們在前面 web 的例子的基礎上來看看怎麼處理 login 頁面的 form 資料

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
    "strings"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()       //解析 url 傳遞的參數,對於 POST 則解析 HTTP 回應內容的主體(request body)
    //注意 : 如果沒有呼叫 ParseForm 方法,下面無法取得表單的資料
    fmt.Println(r.Form) //這些資訊是輸出到伺服器端的列印資訊
    fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)
    fmt.Println(r.Form["url_long"])
    for k, v := range r.Form {
        fmt.Println("key:", k)
        fmt.Println("val:", strings.Join(v, ""))
    }
    fmt.Fprintf(w, "Hello astaxie!") //這個寫入到 w 的是輸出到客戶端的
}

func login(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method) //取得請求的方法
    if r.Method == "GET" {
        t, _ := template.ParseFiles("login.gtpl")
        log.Println(t.Execute(w, nil))
    } else {
        //請求的是登入資料,那麼執行登入的邏輯判斷
        fmt.Println("username:", r.Form["username"])
        fmt.Println("password:", r.Form["password"])
    }
}

func main() {
    http.HandleFunc("/", sayhelloName)       //設定存取的路由
    http.HandleFunc("/login", login)         //設定存取的路由
    err := http.ListenAndServe(":9090", nil) //設定監聽的埠
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

透過上面的程式碼我們可以看出取得請求方法是透過r.Method來完成的,這是個字串型別的變數,回傳 GET, POST, PUT 等 method 資訊。

login 函式中我們根據r.Method來判斷是顯示登入介面還是處理登入邏輯。當 GET 方式請求時顯示登入介面,其他方式請求時則處理登入邏輯,如查詢資料庫、驗證登入資訊等。

當我們在瀏覽器裡面開啟http://127.0.0.1:9090/login的時候,出現如下介面

如果你看到一個空頁面,可能是你寫的 login.gtpl 檔案中有錯誤,請根據控制檯中的日誌進行修復。

圖 4.1 使用者登入介面

我們輸入使用者名稱和密碼之後發現在伺服器端是不會顯示出來任何輸出的,為什麼呢?預設情況下,Handler 裡面是不會自動解析 form 的,必須明確的呼叫r.ParseForm()後,你才能對這個表單資料進行操作。我們修改一下程式碼,在fmt.Println("username:", r.Form["username"])之前加一行r.ParseForm(),重新編譯,再次測試輸入提交,現在是不是在伺服器端有輸出你的輸入的使用者名稱和密碼了。

r.Form裡面包含了所有請求的參數,比如 URL 中 query-string、POST 的資料、PUT 的資料,所以當你在 URL 中的 query-string 欄位和 POST 衝突時,會儲存成一個 slice,裡面儲存了多個值,Go 官方文件中說在接下來的版本里面將會把 POST、GET 這些資料分離開來。

現在我們修改一下 login.gtpl 裡面 form 的 action 值http://127.0.0.1:9090/login修改為http://127.0.0.1:9090/login?username=astaxie,再次測試,伺服器的輸出 username 是不是一個 slice。伺服器端的輸出如下:

圖 4.2 伺服器端列印接收到的資訊

request.Form是一個 url.Values 型別,裡面儲存的是對應的類似 key=value 的資訊,下面展示了可以對 form 資料進行的一些操作:

v := url.Values{}
v.Set("name", "Ava")
v.Add("friend", "Jess")
v.Add("friend", "Sarah")
v.Add("friend", "Zoe")
// v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe"
fmt.Println(v.Get("name"))
fmt.Println(v.Get("friend"))
fmt.Println(v["friend"])

Tips: Request 本身也提供了 FormValue()函式來取得使用者提交的參數。如 r.Form["username"]也可寫成 r.FormValue("username")。呼叫 r.FormValue 時會自動呼叫 r.ParseForm,所以不必提前呼叫。r.FormValue 只會回傳同名參數中的第一個,若參數不存在則回傳空字串。

links

Previous表單Next驗證表單的輸入

Last updated 4 years ago

Was this helpful?

上一節:

下一節:

目錄
表單
驗證表單的輸入