Files
build-web-application-with-…/zh-tw/04.1.md
2019-02-26 01:40:54 +08:00

113 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 4.1 處理表單的輸入
先來看一個表單遞交的例子我們有如下的表單內容命名成檔案login.gtpl(放入當前新建專案的目錄裡面)
```html
<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資料
```Go
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"strings"
)
func sayhelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析url傳遞的引數對於POST則解析響應套件的主體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`的時候,出現如下介面
![](images/4.1.login.png?raw=true)
如果你看到一個空頁面,可能是你寫的 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。伺服器端的輸出如下
![](images/4.1.slice.png?raw=true)
圖4.2 伺服器端列印接收到的資訊
`request.Form`是一個url.Values型別裡面儲存的是對應的類似`key=value`的資訊下面展示了可以對form資料進行的一些操作:
```Go
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
* [目錄](<preface.md>)
* 上一節: [表單](<04.0.md>)
* 下一節: [驗證表單的輸入](<04.2.md>)