goweb-表单
表单
简单的处理一个登陆界面
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-表单的更多相关文章
- go-web 获取get/post请求中的请求头和表单数据
package main import ( "fmt" "net/http" ) func handler(w http.ResponseWriter, r * ...
- Go-Web编程_表单_0x02_验证表单的输入
开发Web的一个原则就是,不能信任用户输入的任何信息,所以验证和过滤用户的输入信息就变得非常重要,我们经常会在微博.新闻中听到某某网站被入侵了,存在什么漏洞,这些大多是因为网站对于用户输入的信息没有做 ...
- ASP.NET Aries 入门开发教程9:业务表单的开发
前言: 经过前面那么多篇的列表的介绍,终于到了大伙期待的表单开发了. 也是本系列的最后一篇文章了! 1:表单页面的权限设置与继承 对于表单页面,权限的设置有两种: 1:你可以选择添加菜单(设置为不显示 ...
- 探索ASP.NET MVC5系列之~~~3.视图篇(下)---包含常用表单和暴力解猜防御
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- jQuery学习之路(8)- 表单验证插件-Validation
▓▓▓▓▓▓ 大致介绍 jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的验证方法,包括 ...
- jQuery学习之路(5)- 简单的表单应用
▓▓▓▓▓▓ 大致介绍 接下来的这几个博客是对前面所学知识的一个简单的应用,来加深理解 ▓▓▓▓▓▓ 单行文本框 只介绍一个简单的样式:获取和失去焦点改变样式 基本结构: <form actio ...
- 12、Struts2表单重复提交
什么是表单重复提交 表单的重复提交: 若刷新表单页面, 再提交表单不算重复提交. 在不刷新表单页面的前提下: 多次点击提交按钮 已经提交成功, 按 "回退" 之后, 再点击 &qu ...
- .net erp(办公oa)开发平台架构概要说明之表单设计器
背景:搭建一个适合公司erp业务的开发平台. 架构概要图: 表单设计开发部署示例图 表单设计开发部署示例说明1)每个开发人员可以自己部署表单设计至本地一份(当然也可以共用一套开发环境,但是如 ...
- javascript表单的Ajax 提交插件的使用
Ajax 提交插件 form.js 表单的下载地址:官方网站:http://malsup.com/jquery/form/ form.js 插件有两个核心方法:ajaxForm()和ajaxSubmi ...
- 玩转spring boot——AOP与表单验证
AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...
随机推荐
- MFC 根据字符宽度居中
Gdiplus::Font font(_T("微软雅黑"), (Gdiplus::REAL)130); Gdiplus::RectF orgin(0.0f, 100.0f, nWi ...
- Kubernetes-基于helm安装部署高可用的Redis及其形态探索(二)
上一章,我们通过实践和其他文章的帮助,在k8s的环境安装了redis-ha,并且对其进行了一些实验来验证他的主从切换是否有效.本篇中将会分析,究竟是如何实现了redis-ha的主从切换,以及其与K8S ...
- 实验吧Web-中-登陆一下好吗??
题目上说:不要怀疑,我已经过滤了一切,还再逼你注入,哈哈哈哈哈! 可以试试,只要是输入的关键字都被过滤了,双写也被过滤掉了. 用万能密码发现,or被过滤掉了. 这里用到的是admin为:'=',密码为 ...
- DevOps专题|玩转Kubernetes网络
Kubernetes无疑是当前最火热的容器编排工具,网络是kubernetes中非常重要的一环, 本文主要介绍一些相应的网络原理及术语,以及kubernetes中的网络方案和对比. Kubernete ...
- 一行python代码能写出啥?
1.一行代码启动一个Web服务 python -m SimpleHTTPServer 8080 # python2 python3 -m http.server 8080 # python3 2. ...
- CSU2004:Finding words(含指定不相交前后缀的模式串计数)
题:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2004 题意:给定n个模式串,m个询问,每个询问是“前缀+‘*’+后缀 ”的组合的串S,输出 ...
- Java底层魔术类Unsafe用法简述
1 引子 Java中没有指针,不能直接对内存地址的变量进行控制,但Java提供了一个特殊的类Unsafe工具类来间接实现.Unsafe主要提供一些用于执行低级别.不安全操作的方法,如直接访问系统内存资 ...
- 编写软件动态加载NT式驱动
NT式设备驱动程序的动态加载主要是由服务控制管理程序(Service Control Manager,即SCM)系统组件来完成的. Windwos服务可以在系统启动时加载,用户也可以按需在服务控制平台 ...
- Bugku杂项(1—28)
1.签到题 只要关注公众号就可以得到 flag---开胃菜 2.这是一张单纯的图片 用Winhex打开,会发现最下面有一行编码: key{you are right} 是一串HTML编码,解密下就行了 ...
- 吴裕雄--天生自然 JAVASCRIPT开发学习: DOM - 改变 HTML
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...