Golang Web學(xué)習(xí)(14)—— 表單處理

本文為轉(zhuǎn)載,原文:Golang Web學(xué)習(xí)(14)—— 表單處理

Golang

介紹

表單是我們平常編寫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é)果:


表單輸入

校驗結(jié)果

源碼

github 源碼地址

轉(zhuǎn)載請注明出處:
Golang Web學(xué)習(xí)(14)—— 表單處理

目錄
上一節(jié):Golang Web學(xué)習(xí)(13)—— 搭建簡單的Web服務(wù)器
下一節(jié):Golang Web學(xué)習(xí)(15)—— 文件上傳

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市冷溃,隨后出現(xiàn)的幾起案子掠哥,更是在濱河造成了極大的恐慌,老刑警劉巖秃诵,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件续搀,死亡現(xiàn)場離奇詭異,居然都是意外死亡菠净,警方通過查閱死者的電腦和手機禁舷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門彪杉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牵咙,你說我怎么就攤上這事派近。” “怎么了洁桌?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵渴丸,是天一觀的道長。 經(jīng)常有香客問我另凌,道長谱轨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任吠谢,我火速辦了婚禮土童,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘工坊。我一直安慰自己献汗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布王污。 她就那樣靜靜地躺著罢吃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昭齐。 梳的紋絲不亂的頭發(fā)上尿招,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音司浪,去河邊找鬼泊业。 笑死,一個胖子當(dāng)著我的面吹牛啊易,可吹牛的內(nèi)容都是我干的吁伺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼租谈,長吁一口氣:“原來是場噩夢啊……” “哼篮奄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起割去,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窟却,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后呻逆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夸赫,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年咖城,在試婚紗的時候發(fā)現(xiàn)自己被綠了茬腿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呼奢。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖切平,靈堂內(nèi)的尸體忽然破棺而出握础,到底是詐尸還是另有隱情,我是刑警寧澤悴品,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布禀综,位于F島的核電站,受9級特大地震影響苔严,放射性物質(zhì)發(fā)生泄漏定枷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一邦蜜、第九天 我趴在偏房一處隱蔽的房頂上張望依鸥。 院中可真熱鬧亥至,春花似錦悼沈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至茶敏,卻和暖如春壤靶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惊搏。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工贮乳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恬惯。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓向拆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親酪耳。 傳聞我的和親對象是個殘疾皇子浓恳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355