GO Web编程(四——表单)

原文作者:Go 技术论坛文档:《Go Web 编程()》
转自链接:https://learnku.com/docs/build-web-application-with-golang/4-form/3173

  • 预防跨站脚本

func HTMLEscape (w io.Writer, b [] byte) // 把 b 进行转义之后写到 w
func HTMLEscapeString (s string) string // 转义 s 之后返回结果字符串
func HTMLEscaper (args ...interface {}) string // 支持多个参数一起转义,返回结果字符串

fmt.Println("username:", template.HTMLEscapeString(r.Form.Get("username"))) // 输出到服务器端
fmt.Println("password:", template.HTMLEscapeString(r.Form.Get("password")))
template.HTMLEscape(w, []byte(r.Form.Get("username"))) // 输出到客户端
  • 验证表单的输入

我们平常编写 Web 应用主要有两方面的数据验证,一个是在页面端的 js 验证 (目前在这方面有很多的插件库,比如 ValidationJS 插件),一个是在服务器端的验证。

  • 必填字段

确保从表单元素中得到一个值

if len(r.Form["username"][0])==0{
    //值为空的处理
}
  • 数字
getint,err := strconv.Atoi(r.Form.Get("age"))
if err!=nil{
    // 数字转化出错了,那么可能就不是数字
}

// 接下来就可以判断这个数字的大小范围了
if getint >100 {
    // 太大了
}

//正则匹配:
if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m {
    return false
}
  • 正则表达式
//手机号
if m, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]\d{4,8})$`,r.Form.Get("mobile")); !m {
    return false
}
//电子邮件
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")
}
  • 下拉菜单

判断表单里的<select>的值是否是预设的值

<select name="fruit">
<option value="apple">apple</option>
<option value="pear">pear</option>
<option value="banana">banana</option>
</select>

验证:

slice := []string{"apple","pear","banana"}
v:= r.Form.Get("fruit")
for _,item := range slice {
    if item == v{
        return true
    }
}
return false
  • 防止多次递交表单

解决方案:在表单中添加一个带有唯一值的隐藏字段。在验证表单时,检查该唯一值是否已经提交过,如果是就拒绝再次提交。

<input type="hidden" name="token" value="{{.}}">
 r.ParseForm()
        token := r.Form.Get("token")
        if token != "" {
            // 验证 token 的合法性
        } else {
            // 不存在 token 报错
        }
  • 处理文件上传
http.HandleFunc("/upload", upload)

// 处理 /upload  逻辑
func upload(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method) // 获取请求的方法
    if r.Method == "GET" {
        crutime := time.Now().Unix()
        h := md5.New()
        io.WriteString(h, strconv.FormatInt(crutime, 10))
        token := fmt.Sprintf("%x", h.Sum(nil))

        t, _ := template.ParseFiles("upload.gtpl")
        t.Execute(w, token)
    } else {
        r.ParseMultipartForm(32 << 20)
        file, handler, err := r.FormFile("uploadfile")
        if err != nil {
            fmt.Println(err)
            return
        }
        defer file.Close()
        fmt.Fprintf(w, "%v", handler.Header)
        f, err := os.OpenFile("./test/"+handler.Filename,os.O_WRONLY|os.O_CREATE, 0666)  // 此处假设当前目录下已存在test目录
        if err != nil {
            fmt.Println(err)
            return
        }
        defer f.Close()
        io.Copy(f, file)
    }
}

上传文件的三步处理:

1、表单中增加enctype="multipat/form-data"

2、服务端调用r.ParseMultipartForm,把上传的文件存储在内存和临时文件中

3、使用r.FormFile获取文件句柄

posted @ 2021-05-12 18:51  Gumi-21  阅读(98)  评论(0)    收藏  举报