Go HTTP 编程 | 03 - 表单的输入与验证

2022-11-25 11:33:44 浏览数 (1)

一、表单的输入

表单是 Web 应用中非常中重要的组成部分,通过表单可以方法的让客户端和服务器进行数据的交互。Go 中对于 form 的处理非常方便,在 Request 中有专门的 form 处理方法。

以登录表单为例,新建一个登录表达 login.gtpl,表单内容如下:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Login Form</title>
</head>
<body>
<form action="http://localhost:9000/login" method="post">
    USERNAME:<input type="text" name="username"> <br>
    PASSWORD:<input type="password" name="password"> <br>
    <input type="submit" value="Sing In">
</form>
</body>
</html>

上述表单收集的信息将会递交到服务器的 /login,当用户输出信息并点击登录的时候,会跳转到服务器的路由 login 里面,所以服务器首先要判断请求时 POST 还是 GET

http 包中有一个简单的方法可以获取请求方式 r.Method 方法,main.go 文件的代码如下:

代码语言:javascript复制
import (
   "fmt"
   "html/template"
   "log"
   "net/http"
   "strings"
)

//noinspection ALL
func main(){
   http.HandleFunc("/login", login)

   err := http.ListenAndServe(":9000", nil)

   if err != nil {
      log.Fatal("ListenAndServe: ", err)
   }
}


func login(w http.ResponseWriter, r *http.Request){
   fmt.Println("method", r.Method) // 获取请求的方式

   // GET 请求,跳转至登录界面
   if r.Method == "GET" {
      t, _ := template.ParseFiles("form/login.gtpl")
      t.Execute(w, nil)
   } else {
      // 请求的是登录数据,执行登录逻辑
      r.ParseForm()
      fmt.Println("Form Data:", r.Form)
      fmt.Println("username: ", r.Form["username"])
      fmt.Println("password: ", r.Form["password"])
   }
}

上述代码中的 login 方法通过判断语句判断请求方式,如果是 GET 请求则跳转到 login 界面,注意这里填写 login.gtpl 文件的位置一定要准确,否则会报错。

如果不是 GET 请求则会处理提交的数据,其中 r.ParseForm() 会解析 URL,针对 POST 请求则会解析请求体,若没有这一行代码是无法获取的 POST 请求提交的参数的,最后会将提交的数据输出到控制台。

接着就是 main 函数中的路由和端口配置。执行 main 函数启动 Web 服务,在浏览器中输入 localhost:9000/login,浏览器显示如下页面:

当是 GET 请求时显示登录页面,输入用户名和密码,点击提交;此时是 POST 请求,则会执行 esle 代码块,即将提交的信息输出到控制台:

二、表单的验证

在获取到了用户提交的数据之后,存储到数据库之前,需要对用户提交的数据进行校验,校验可以在前端通过 JavaScript 实现,也可以在服务端进行校验。

必填字段

针对表单中的必填字段,可以通过获取提交的数据的长度来判断提交的数据是否为空:

代码语言:javascript复制
if len(r.Form["username"][0]) == 0 {
    // 字符串为空的处理
}

r.Form 对不同类型的表单元素的留空有不同的处理,对于空文本框、空文本区域以及文件上传,元素的值为空值,而如果是未选中的复选框和单选按钮,则根本不会在 r.Form 中产生相应的条目,在实际获取程序值的时候需要通过 r.Form.Get() 来获取,若字段不存在,则获取的是空值,但是通过这种方式只能获取单个的值,如果是 map 还需要通过 r.Form["username"][0] 这种方式获取。

数字

如果要确保单选框中的输入只能是数字类型,比如获取用户的年龄,可以先转换成 int 类型,然后在处理:

代码语言:javascript复制
age, err := strconv.Atoi(r.Form.Get("age"))

if err != nil {
    // 转换为 int 类型出错,说明用户的输入不是数字
}

// 用户输入的数字转换成功,进行下一步操作
if age > 100 {
    // 年龄超过指定范围
}

还可以通过正则表达式的方式来获取:

代码语言:javascript复制
if m, _ := regexp.MatchString("^[0-9] $", r.Form.Get("age")); !m {
    return false
}

但是正则表达式的速度相对来说会比较慢。

中文和英文

如果想要获取表单中的中文字符,并确保获取的是正确的中文字符,需要进行验证,而不是随便输入,中文只有通过正则来验证:

代码语言:javascript复制
if m, _ := regexp.MatchString("^[\x{4e00}-\x{9fa5}] $", r.Form.Get("chineseName")); !m {
    return false
}

如果要获取表单中的英文值,也可以通过正则表达式:

代码语言:javascript复制
if m, _ := regexp.MatchString("^[a-zA-Z] $", r.Form.Get("firstName")); !m {
    return false
}

Email, 电话号码和电话号码

验证用户输入的 Email 是否正确,可以通过以下方式验证:

代码语言:javascript复制
if m, _ := regexp.MatchString(`^([w._]{2,10})@(w{1,}).([a-z]{2,4})$`,

r.Form.Get("email")); !m {
    fmt.Println("no")
}else{
    fmt.Println("yes")
}

手机号码可以通过如下方式验证:

代码语言:javascript复制
if m, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]d{4,8})$`, r.Form.Get("mobile")); !
m {
    return false
}

对身份证号码,可以通过如下方式验证:

代码语言:javascript复制
//验证 15 位身份证,15 位的是全部数字

if m, _ := regexp.MatchString(`^(d{15})$`, r.Form.Get("usercard")); !m {
    return false
}

//验证 18 位身份证,18 位前 17 位为数字,最后一位是校验位,可能为数字或字符 X。

if m, _ := regexp.MatchString(`^(d{17})([0-9]|X)$`, r.Form.Get("usercard")); !m {
    return false
}

日期与时间

想要判断用户输入的时间是否正确,可以使用 Go 的 time 包,可以将用户的输入转换成相应的时间,然后进行逻辑判断:

代码语言:javascript复制
t := time.Date(2022, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf(t.Local())

转换成 Go 的时间就可以进行更多的操作了

下拉菜单,单选按钮和复选框

想要判断下拉菜单中是否有条目被选中,比如 select 是这样的:

代码语言:javascript复制
<select name="fruit">
    <option value="apple">apple</option>
    <option value="pear">pear</option>
    <option value="banane">banane</option>
</select>

如何判断用户提交的值是 option 其中的一个呢?

代码语言:javascript复制
slice := []string{"apple", "pear", "banane"}

for _, v := range slice {
    if v == r.Form.Get("fruit") {
           return true
    }
}
return false

针对单选框判断发送的值为预设的值可以使用如下方式:

代码语言:javascript复制
<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女

也是通过遍历的方式判断

代码语言:javascript复制
slice:=[]int{1,2}

for _, v := range slice {
    if v == r.Form.Get("gender") {
        return true
    }
}

return false

针对复选框的判断有一点不一样,因为复选框接收到的是一个 Slice

代码语言:javascript复制
<input type="checkbox" name="interest" value="football">足球
<input type="checkbox" name="interest" value="basketball">篮球
<input type="checkbox" name="interest" value="tennis">网球
代码语言:javascript复制
slice:=[]string{"football","basketball","tennis"}

a:=Slice_diff(r.Form["interest"],slice)
    if a == nil{
        return true
    }
return false

0 人点赞