我們前幾天都一直在處理GET請求,今天我們來試著做一個POST表單範例,首先我們需要一個表單的HTML template。我們這次使用gtpl
為副檔名,這是一個專門為了go所做的網頁框架,類似ruby的erb,如果想瞭解更多可以參考github。
我們新建一個檔案,另存為login.grpl
:
<html>
<head>
<title></title>
</head>
<body>
<form action="/login" method="post">
Username:<input type="text" name="username">
Password:<input type="password" name="password">
<input type="submit" value="Submit">
</form>
</body>
</html>
很不幸的,vs code還沒有對gtpl有程式碼高亮支援。從這段程式可以看出這是一個簡單的登入頁面,包裹在一個POST的表單中,有兩個輸入欄位讓使用者輸入用戶名稱與密碼。這邊並沒有真的實作密碼驗證,只是單純把使用者輸入的值印在畫面上。有關與資料庫串接或session,在之後的日子應該會討論到。
接下來我們看看程式的部分:
package main
import (
"fmt"
"html/template"
"log"
"net/http"
)
func main() {
http.HandleFunc("/login", login)
err := http.ListenAndServe(":3000", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
func login(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println("method:", r.Method)
if r.Method == "GET" {
t, _ := template.ParseFiles("./day14/login.gtpl")
log.Println(t.Execute(w, nil))
} else {
// 在這邊放真實的驗證
fmt.Fprint(w, "username: ", r.Form["username"][0])
fmt.Fprint(w, ", password: ", r.Form["password"][0])
}
}
這個範例相當的簡化,只有一個路由,但可以接受兩種action,分別是GET與POST,很符合我們常見的例子:GET作為表單的view本身,POST發送表單內容到後端。
要特別注意幾個地方,r.ParseForm()
這個會解析request內POST的主體,並且把參數讀取出來。如果沒有加上的話編譯不會錯,但是會讀不到參數,使用POST的時候要特別注意!另外r.Method
可以將action讀出來,判斷是GET或是POST進行不同邏輯。
如果我們訪問瀏覽器http://localhost:3000/login(透過瀏覽器時一定是GET),會得到下面的畫面:
非常簡陋我知道,我們目前先不考慮美觀的部分。輸入名稱密碼後,會秀在頁面上:
今天的範例就到這邊,想題目越來越困難啦,希望能繼續堅持下去!
請問http.HandleFunc("/login", login) 這行程式是綁定 func login???
我寫了底下的程式
package main
import (
"time"
"fmt"
"html/template"
"log"
"net/http"
"strings"
)
func sayhelloName(w http.ResponseWriter, r *http.Request) {
currentTime:=time.Now()
fmt.Println("home888============")
fmt.Println(currentTime)
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) {
currentTime:=time.Now()
fmt.Println("login============")
fmt.Println(currentTime)
r.ParseForm()
fmt.Println(r.Form) //這些資訊是輸出到伺服器端的列印資訊
fmt.Println("path", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println("method:", r.Method) //取得請求的方法
if r.Method == "GET" {
t, _ := template.ParseFiles("login.gtpl")
log.Println(t.Execute(w, nil))
} else {
//請求的是登入資料,那麼執行登入的邏輯判斷
fmt.Fprint(w, "username: ", r.Form["username"][0])
fmt.Fprint(w, ", password: ", r.Form["password"][0])
}
}
func main() {
fmt.Println("service start...")
//fmt.Println("path", r.URL.Path)
//fmt.Println("scheme", r.URL.Scheme)
http.HandleFunc("/", sayhelloName) //設定存取的路由
http.HandleFunc("/login", login) //設定存取的路由
err := http.ListenAndServe(":9099", nil) //設定監聽的埠
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
在瀏覽器輸入 http://127.0.0.1:9099/login
後端在處理的時候??還是會處理 home 函數
不知道哪行程式出錯了!!!