当前位置: 萬仟网 > IT编程>脚本编程>Go语言 > goweb-表单

goweb-表单

2020年01月14日 15:01  | 萬仟网IT编程  | 我要评论

表单

简单的处理一个登陆界面

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)
    }
}

request.form是一个url.values类型,里面存储的是对应的类似key=value的信息,下面展示了可以对form数据进行的一些操作:

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"])

request本身也提供了formvalue()函数来获取用户提交的参数。如r.form["username"]也可写成r.formvalue("username")。调用r.formvalue时会自动调用r.parseform,所以不必提前调用。r.formvalue只会返回同名参数中的第一个,若参数不存在则返回空字符串。

服务端表单验证

这一部分讲了验证数字,中文,名字,号码等许多需要验证的东西,主要有:通过正则验证,通过逻辑结构验证并调用相关的包

预防跨站脚本

现在的网站包含大量的动态内容以提高用户体验,比过去要复杂得多。所谓动态内容,就是根据用户环境和需要,web应用程序能够输出相应的内容。动态站点会受到一种名为“跨站脚本攻击”(cross site scripting, 安全专家们通常将其缩写成 xss)的威胁,而静态站点则完全不受其影响。

攻击者通常会在有漏洞的程序中插入javascript、vbscript、 activex或flash以欺骗用户。一旦得手,他们可以盗取用户帐户信息,修改用户设置,盗取/污染cookie和植入恶意广告等。

对xss最佳的防护应该结合以下两种方法:一是验证所有输入数据,有效检测攻击(这个我们前面小节已经有过介绍);另一个是对所有输出数据进行适当的处理,以防止任何已成功注入的脚本在浏览器端运行。

主要通过转义来实现这个,用到text/template和html/template

防止多次递交表单

不知道你是否曾经看到过一个论坛或者博客,在一个帖子或者文章后面出现多条重复的记录,这些大多数是因为用户重复递交了留言的表单引起的。由于种种原因,用户经常会重复递交表单。通常这只是鼠标的误操作,如双击了递交按钮,也可能是为了编辑或者再次核对填写过的信息,点击了浏览器的后退按钮,然后又再次点击了递交按钮而不是浏览器的前进按钮。当然,也可能是故意的——比如,在某项在线调查或者博彩活动中重复投票。那我们如何有效的防止用户多次递交相同的表单呢?

解决方案是在表单中添加一个带有唯一值的隐藏字段。在验证表单时,先检查带有该唯一值的表单是否已经递交过了。如果是,拒绝再次递交;如果不是,则处理表单进行逻辑处理。另外,如果是采用了ajax模式递交表单的话,当表单递交后,通过javascript来禁用表单的递交按钮。

func login(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("login.gtpl")
        t.execute(w, token)
    } else {
        //请求的是登陆数据,那么执行登陆的逻辑判断
        r.parseform()
        token := r.form.get("token")
        if token != "" {
            //验证token的合法性
        } else {
            //不存在token报错
        }
        fmt.println("username length:", len(r.form["username"][0]))
        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"))) //输出到客户端
    }
}

利用唯一性来判断,但并不能防止恶意的攻击

处理文件上传

你想处理一个由用户上传的文件,比如你正在建设一个类似instagram的网站,你需要存储用户拍摄的照片。这种需求该如何实现呢?

要使表单能够上传文件,首先第一步就是要添加form的enctype属性,enctype属性有如下三种情况:

  • application/x-www-form-urlencoded 表示在发送前编码所有字符(默认)
  • multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
  • text/plain 空格转换为 "+" 加号,但不对特殊字符编码。

上传文件主要三步处理:

表单中增加enctype="multipart/form-data"
服务端调用r.parsemultipartform,把上传的文件存储在内存和临时文件中
使用r.formfile获取文件句柄,然后对文件进行存储等处理

go支持模拟客户端表单功能支持文件上传,详细用法请看如下示例:

package main

import (
    "bytes"
    "fmt"
    "io"
    "io/ioutil"
    "mime/multipart"
    "net/http"
    "os"
)

func postfile(filename string, targeturl string) error {
    bodybuf := &bytes.buffer{}
    bodywriter := multipart.newwriter(bodybuf)

    //关键的一步操作
    filewriter, err := bodywriter.createformfile("uploadfile", filename)
    if err != nil {
        fmt.println("error writing to buffer")
        return err
    }

    //打开文件句柄操作
    fh, err := os.open(filename)
    if err != nil {
        fmt.println("error opening file")
        return err
    }
    defer fh.close()
    
    //iocopy
    _, err = io.copy(filewriter, fh)
    if err != nil {
        return err
    }

    contenttype := bodywriter.formdatacontenttype()
    bodywriter.close()

    resp, err := http.post(targeturl, contenttype, bodybuf)
    if err != nil {
        return err
    }
    defer resp.body.close()
    resp_body, err := ioutil.readall(resp.body)
    if err != nil {
        return err
    }
    fmt.println(resp.status)
    fmt.println(string(resp_body))
    return nil
}

// sample usage
func main() {
    target_url := "http://localhost:9090/upload"
    filename := "./astaxie.pdf"
    postfile(filename, target_url)
}

这一章里面我们学习了go如何处理表单信息,我们通过用户登录、上传文件的例子展示了go处理form表单信息及上传文件的手段。但是在处理表单过程中我们需要验证用户输入的信息,考虑到网站安全的重要性,数据过滤就显得相当重要了,因此后面的章节中专门写了一个小节来讲解了不同方面的数据过滤,顺带讲一下go对字符串的正则处理。

客户端和服务器端是如何进行数据上的交互,客户端将数据传递给服务器系统,服务器接受数据又把处理结果反馈给客户端。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • goweb- 国际化和本地化

    国际化和本地化 为了适应经济的全球一体化,作为开发者,我们需要开发出支持多国语言、国际化的Web应用,即同样的页面在不同的语言环境下需要显示不同的效... [阅读全文]
  • goweb-错误处理,调试和测试

    错误处理,调试和测试 我们经常会看到很多程序员大部分的"编程"时间都花费在检查bug和修复bug上。无论你是在编写修改代码还是重构系统,几乎都是花费... [阅读全文]
  • Golang 热编译rizla 插件

    今天在写gin接口的时候,每次添加或修改个接口都需要重启项目才能测试,感觉很麻烦。 因为beego有bee工具,bee run启动项目fsnotif... [阅读全文]
  • goweb-处理静态资源

    处理静态文件 对于 HTML 页面中的 css 以及 js 等静态文件,需要使用使用 net/http 包下的以下 方法来处理 1) StripPr... [阅读全文]
  • go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    go微服务框架kratos学习笔记六(kratos 服务发现 discovery) [toc] 除了上次的warden直连方式外,kratos有另一... [阅读全文]
  • goweb-安装go及配置go

    安装go及配置go 安装go 写这篇博客时,我的电脑的windows已经安装过了go,用的是标准包安装,不过我的linux操作系统还没安装,可以考虑... [阅读全文]
  • goweb-go语言基础

    go语言基础 虽然这本书是讲goweb,但还是吧go语言基础过了一遍,由于我之前已经对go语言基础做了一遍系统的学习,这里就当简单回顾一下,不再写过... [阅读全文]
  • goweb-goweb基础

    goweb DNS工作原理 在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用... [阅读全文]
  • goweb-表单

    表单 简单的处理一个登陆界面 request.Form是一个url.Values类型,里面存储的是对应的类似key=value的信息,下面展示了可以... [阅读全文]
  • goweb-访问数据库

    访问数据库 对许多Web应用程序而言,数据库都是其核心所在。数据库几乎可以用来存储你想查询和修改的任何信息,比如用户信息、产品目录或者新闻列表等。 ... [阅读全文]

◎已有 0 人评论

Copyright © 2020  萬仟网 保留所有权利. 粤ICP备17035492号-1
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com