本文為轉(zhuǎn)載,原文:Golang Web學(xué)習(xí)(14)—— 表單處理
介紹
表單是我們平常編寫Web應(yīng)用常用的工具剑肯,通過表單我們可以方便的讓客戶端和服務(wù)器進 行數(shù)據(jù)的交互齐苛。對于以前開發(fā)過Web的用戶來說表單都非常熟悉炼团。
表單是一個包含表單元素的區(qū)域来屠。表單元素是允許用戶在表單中(比如:文本域、下拉列表榆鼠、 單選框纲爸、復(fù)選框等等)輸入信息的元素。表單使用表單標簽(<form>
)定義妆够。
1识啦、處理表單的輸入
先看一個例子吧。
在之前文章的代碼基礎(chǔ)之下神妹,創(chuàng)建一個view文件夾颓哮,用來存放界面的代碼文件,在view文件中創(chuàng)建一個login.ctpl文件鸵荠,用來寫前端代碼冕茅,后綴名可根據(jù)自己喜好自定義。下面看下這個文件內(nèi)的代碼:
<html>
<head>
<title>登錄</title>
</head>
<body>
<form action="http://localhost:9090/login" method="post">
用戶名:<input type="text" name="username">
密碼:<input type="password" name="password">
<input type="submit" value="登陸">
</form>
</body>
</html>
從代碼中可知蛹找,我們的界面非常簡單姨伤,就是個簡單的用戶名,密碼的表單庸疾,且通過Post方法提交到http://localhost:9090/login
乍楚。
然后我們再看一下這個后端對于login的處理,同樣在之前的代碼基礎(chǔ)上届慈,在myserver.go
文件中添加一個login的函數(shù)徒溪。
代碼如下:
func login(w http.ResponseWriter, r *http.Request){
r.ParseForm() //解析form
fmt.Println("method: ", r.Method)
//判斷傳遞方式
if r.Method == "GET"{
//加載界面模板
t, _ := template.ParseFiles("./view/login.ctpl")
//將解析好的模板應(yīng)用到data上,這里data為nil
t.Execute(w, nil)
}else if r.Method == "POST"{
fmt.Println("username: ", r.Form["username"])
fmt.Println("password: ", r.Form["password"])
}
}
當(dāng)代碼執(zhí)行到login函數(shù)的時候金顿,首先我們要判斷是通過什么方式傳遞過來的词渤,是GET,還是POST串绩。這個我們可以在r.Method
中取得缺虐,然后根據(jù)不同的方法分別處理。
在get方法中礁凡,我們調(diào)用了html/template
包中的2個函數(shù)高氮,下面看下這兩個函數(shù)的定義吧:
- ParseFiles
func (t *Template) ParseFiles(filenames ...string) (*Template, error)
ParseFiles方法解析filenames指定的文件里的模板定義并將解析結(jié)果與t關(guān)聯(lián)。如果發(fā)生錯誤顷牌,會停止解析并返回nil剪芍,否則返回(t, nil)。至少要提供一個文件窟蓝。
- Execute
func (t *Template) Execute(wr io.Writer, data interface{}) error
Execute方法將解析好的模板應(yīng)用到data上罪裹,并將輸出寫入wr。如果執(zhí)行時出現(xiàn)錯誤,會停止執(zhí)行状共,但有可能已經(jīng)寫入wr部分數(shù)據(jù)套耕。模板可以安全的并發(fā)執(zhí)行。
在Post方法中峡继,這里只是做了簡單的控制臺打印冯袍,檢測是否跟我們輸入的一致。
好碾牌,我們的login函數(shù)寫好了康愤,那么我們怎么調(diào)用呢?當(dāng)然是路由嘍舶吗,在之前的自定義的路由中加入一個新的路由征冷,補充myserver.go
中的ServeHTTP
代碼如下:
func (p *MyMux)ServeHTTP(w http.ResponseWriter, r *http.Request){
if r.URL.Path == "/"{
sayHelloName(w, r)
return
}
if r.URL.Path == "/about"{
about(w, r)
return
}
if r.URL.Path == "/login"{
login(w,r)
return
}
http.NotFound(w,r)
return
}
然后運行,跑起來誓琼。瀏覽器地址欄中輸入:http://localhost:9090/login
资盅,結(jié)果如下:
在頁面中輸入:用戶名:chain 密碼:123456 并點擊登錄按鈕∮辉控制臺結(jié)果如下:
如圖所示呵扛,我們打印出來了我們的輸入。
request.Form是一個url.Values類型筐带,里面存儲的是對應(yīng)的類似key=value的信息今穿,下面 展示了可以對form數(shù)據(jù)進行的一些操作:
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()函數(shù)來獲取用戶提交的參數(shù)。如 r.Form["username"]也可寫成r.FormValue("username")蓝晒。調(diào)用r.FormValue時會自動調(diào)用 r.ParseForm,所以不必提前調(diào)用帖鸦。r.FormValue只會返回同名參數(shù)中的第一個芝薇,若參數(shù)不存 在則返回空字符串。
2作儿、驗證表單的輸入
開發(fā)Web的一個原則就是洛二,不能信任用戶輸入的任何信息,所以驗證和過濾用戶的輸入信 息就變得非常重要攻锰,我們經(jīng)常會在微博晾嘶、新聞中聽到某某網(wǎng)站被入侵了,存在什么漏洞娶吞,這 些大多是是因為網(wǎng)站對于用戶輸入的信息沒有做嚴格的驗證引起的垒迂,所以為了編寫出安全 可靠的Web程序,驗證表單輸入的意義重大妒蛇。
我們平常編寫Web應(yīng)用主要有兩方面的數(shù)據(jù)驗證机断,一個是在頁面端的js驗證(目前在這方 面有很多的插件庫楷拳,比如ValidationJS插件),一個是在服務(wù)器端的驗證吏奸,我們這小節(jié)講解 的是如何在服務(wù)器端驗證欢揖。
必填字段
通過len函數(shù)獲取表單字段長度來判斷字段是否為空:
if len(r.Form["username"][0])==0{
//為空的處理
}
r.Form對不同類型的表單元素的留空有不同的處理, 對于空文本框苦丁、空文本區(qū)域以及文件 上傳浸颓,元素的值為空值,而如果是未選中的復(fù)選框和單選按鈕物臂,則根本不會在r.Form中產(chǎn)生 相應(yīng)條目旺拉,如果我們用上面例子中的方式去獲取數(shù)據(jù)時程序就會報錯。所以我們需要通過 r.Form.Get()來獲取值棵磷,因為如果字段不存在蛾狗,通過該方式獲取的是空值。但是通過 r.Form.Get()只能獲取單個的值仪媒,如果是map的值沉桌,必須通過上面的方式來獲取。
數(shù)字
如果我們是判斷正整數(shù)算吩,那么我們先轉(zhuǎn)化成int類型留凭,然后進行處理
age, err := strconv.Atoi(r.Form.Get("age"))
if err != nil{
fmt.Fprintf(w, "The format of the input is not correct")
}
if age < 18{
fmt.Fprintf(w, "Minors are not registered")
}
下拉框,復(fù)選框偎巢,單選框
這種的校驗可以預(yù)先在服務(wù)端創(chuàng)建與客戶端選項一致的切片蔼夜,當(dāng)客戶端提交的時候再與服務(wù)端的相比較,決策出輸入是否合理压昼。
正則表達式
對于一些復(fù)雜的字符串可能需要用正則表達式來匹配
if m, _ := regexp.MatchString(`表達式字符串`,
r.Form.Get("key")); !m {
//錯誤處理
}
下面提供幾種正則匹配規(guī)則:
- 中文匹配
^[\\x{4e00}-\\x{9fa5}]+$
- 英文
^[a-zA-Z]+$
- 郵箱
`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`
- 手機號碼
`^(1[3|4|5|8][0-9]\d{4,8})$`
- 身份證號碼
//驗證15位身份證求冷,15位的是全部數(shù)字
`^(\d{15})$`
//驗證18位身份證,18位前17位為數(shù)字窍霞,最后一位是校驗位匠题,可能為數(shù)字或字符X。
`^(\d{17})([0-9]|X)$`
例子
修改下之前的login.ctpl和login函數(shù)的代碼但金,測試下我們的表單驗證韭山。
login.ctpl:
<html>
<head>
<title></title>
</head>
<body>
<form action="http://localhost:9090/login" method="post">
用戶名:<input type="text" name="username">
年齡:<input type="number" name="age">
郵箱:<input type="text" name="email">
<input type="submit" value="按鈕">
</form>
</body>
</html>
login函數(shù)
func login(w http.ResponseWriter, r *http.Request){
r.ParseForm() //解析form
fmt.Println("method: ", r.Method)
if r.Method == "GET"{
t, _ := template.ParseFiles("./view/login.ctpl")
t.Execute(w, nil)
}else if r.Method == "POST"{
if len(r.Form["username"][0])==0{
fmt.Fprintf(w, "username: null or empty \n")
}
age, err := strconv.Atoi(r.Form.Get("age"))
if err != nil{
fmt.Fprintf(w, "age: The format of the input is not correct \n")
}
if age < 18{
fmt.Fprintf(w, "age: Minors are not registered \n")
}
if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`,
r.Form.Get("email")); !m {
fmt.Fprintf(w, "email: The format of the input is not correct \n")
}
}
}
運行結(jié)果:
源碼
完
轉(zhuǎn)載請注明出處:
Golang Web學(xué)習(xí)(14)—— 表單處理
目錄
上一節(jié):Golang Web學(xué)習(xí)(13)—— 搭建簡單的Web服務(wù)器
下一節(jié):Golang Web學(xué)習(xí)(15)—— 文件上傳