对Golang中的FORM相关字段理解


Posted in Golang onMay 02, 2021

Form 字段

通过调用Request结构体提供的方法,我们可以将URL、Body、或者以上两者的数据提取到该结构体的Form、PostForm和MultipartForm等字段中。

(1)调用ParseForm方法或者ParseMultipartForm方法,对请求进行分析

(2)访问相应的字段

事例:

package main
import (
 "net/http"
 "fmt"
)
func process(w http.ResponseWriter, r *http.Request) {
 r.ParseForm()
 //ParseForm 对请求进行语法分析
 fmt.Fprintln(w,r.MultipartForm)
}
func main() {
 server := http.Server{
  Addr:"127.0.0.1:8080",
 }
 http.HandleFunc("/process",process)
 server.ListenAndServe()
}

创建一个具体表单

<!DOCTYPE html>
<html>
<head>
 <meta  http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>GoWebPrograming</title>
</head>
<body>
 <form action="http://127.0.0.1:8080/process?hello=world&thread=get"
 method="post" enctype="application/x-www-form-urlencoded">
  <input type="text" name="hello"  value="你好 世界"/>
  <input type="text" name="post" value="456" />
  <input type="submit" />
 </form>
</body>
</html>

我们在浏览器运行html文件,结果为:

map[hello:[你好 世界 world] post:[456] thread:[get]]

我们发现这个结构是一个map,他的键为字符串,而建的值是由字符串组成的一个切片。

这个结构总是包含查询的值hello=world, thread=get,还有表单值hello=123和post=456,这些值都进行了url的解码。

比如你好世界之间有空格,说明不是编码之后的%20。

PostForm 字段

执行语句r.Form[“post”]会返回一个切片,切片里包含了表单提交的数据和url中的数据就像“你好世界”和“world” 是一组切片值。但是表单值在切片中总会排在url之前。 ( hello:[你好 世界 world] )

如果我们只想获得表单值而不是url的值,我们可以使用Request结构的PostForm字段,

我们将r.Form 改为 r.PostForm 会出现如下结果

map[hello:[你好 世界] post:[456]]

我们将 enctype="application/x-www-form-urlencoded"改为 enctype=“multipart/form-data”, 结果如下:

map[]

会得到一个空的map,这是为什么呢???

如果我们将 enctype="application/x-www-form-urlencoded"改为 enctype=“multipart/form-data”,并改回 r.Form。会出现以下结果:

map[hello:[world] thread:[get]]

这是因为ParseForm字段只支持"application/x-www-form-urlencoded"编码,所以r.Form不会反悔任何表单值,而是只返回url的查询值。

为了解决这个问题,我们需要通过MultipartForm字段来获取multipart/form-data编码的表单值。

补充:go通过http发送form-data

首先是获取form-data内容

func ResendFormFile(r *http.Request, URL string) {
 data := r.FormValue("data")
 formFile, fileHeader, err := r.FormFile("pic")
 if err != nil {
  return
 }
 _, status := RequestPost(formFile, fileHeader.Filename, []byte(data), URL)
 if (status / 100) != 2 {
  fmt.Println("转发图片失败")
 }
 return
}

然后是发送

func RequestPost(formFile multipart.File, filename string, data []byte, postURL string) (resp interface{}, status int) {
 buf := new(bytes.Buffer)
 w := multipart.NewWriter(buf)
 if fw, err := w.CreateFormField("data"); err == nil {
  fw.Write(data)
 }
 if createFormFile, err := w.CreateFormFile("pic", filename); err == nil {
  readAll, _ := ioutil.ReadAll(formFile)
  createFormFile.Write(readAll)
 }
 w.Close()
 req, err := http.NewRequest(http.MethodPost, postURL, buf)
 if err != nil {
  return
 }
 // Don't forget to set the content type, this will contain the boundary.
 req.Header.Set("Content-Type", w.FormDataContentType())
 client := &http.Client{}
 res, err := client.Do(req)
 if err != nil {
  return
 }
 return res.Body, res.StatusCode
}

这样返回的body是不可以直接json序列化的

可以先使用ioutil读出来或者byte.Buffer进行中转都是比较简单的选择

func UnmarshalWriter(body io.ReadCloser, w http.ResponseWriter) {
 all, _ := ioutil.ReadAll(body)
 buffer := bytes.NewBuffer(all)
 buffer.WriteTo(w)
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
golang http使用踩过的坑与填坑指南
Apr 27 Golang
使用Golang的channel交叉打印两个数组的操作
Apr 29 Golang
go语言中GOPATH GOROOT的作用和设置方式
May 05 Golang
go语言中fallthrough的用法说明
May 06 Golang
goland 设置project gopath的操作
May 06 Golang
解决goland 导入项目后import里的包报红问题
May 06 Golang
Golang标准库syscall详解(什么是系统调用)
May 25 Golang
Golang 语言控制并发 Goroutine的方法
Jun 30 Golang
go goroutine 怎样进行错误处理
Jul 16 Golang
详解Golang如何优雅的终止一个服务
Mar 21 Golang
Golang日志包的使用
Apr 20 Golang
go goth封装第三方认证库示例详解
Aug 14 Golang
解决go在函数退出后子协程的退出问题
Apr 30 #Golang
Go语言 go程释放操作(退出/销毁)
golang DNS服务器的简单实现操作
golang slice元素去重操作
Apr 30 #Golang
Golang中interface{}转为数组的操作
Apr 30 #Golang
解决Go gorm踩过的坑
Apr 30 #Golang
Golang 如何实现函数的任意类型传参
Apr 29 #Golang
You might like
Terran兵种介绍
2020/03/14 星际争霸
最新用php获取谷歌PR值算法,附上php查询PR值代码示例
2011/12/25 PHP
彻底删除thinkphp3.1案例blog标签的方法
2014/12/05 PHP
php无限级分类实现方法分析
2016/10/19 PHP
PHP根据树的前序遍历和中序遍历构造树并输出后序遍历的方法
2017/11/10 PHP
jQuery使用手册之 事件处理
2007/03/24 Javascript
javascript的offset、client、scroll使用方法详解
2012/12/25 Javascript
JS在textarea光标处插入文本的小例子
2013/03/22 Javascript
Highcharts 非常实用的Javascript统计图demo示例
2013/07/03 Javascript
jquery delay()介绍及使用指南
2014/09/02 Javascript
jquery移动节点实例
2015/01/14 Javascript
常用原生JS兼容性写法汇总
2016/04/27 Javascript
WEB开发之注册页面验证码倒计时代码的实现
2016/12/15 Javascript
JS中parseInt()和map()用法分析
2016/12/16 Javascript
js通过keyCode值判断单击键盘上某个键,然后触发指定的事件方法
2017/02/19 Javascript
微信小程序实现文字跑马灯效果
2020/05/26 Javascript
Vue自定义指令实现checkbox全选功能的方法
2018/02/28 Javascript
Vue触发式全局组件构建的方法
2018/11/28 Javascript
微信小程序实现文字跑马灯
2020/05/26 Javascript
使用 JavaScript 创建并下载文件(模拟点击)
2019/10/25 Javascript
python实现人人网登录示例分享
2014/01/19 Python
在Python编程过程中用单元测试法调试代码的介绍
2015/04/02 Python
Python贪吃蛇游戏编写代码
2020/10/26 Python
Django使用redis缓存服务器的实现代码示例
2019/04/28 Python
django foreignkey外键使用的例子 相当于left join
2019/08/06 Python
python函数中将变量名转换成字符串实例
2020/05/11 Python
keras.layer.input()用法说明
2020/06/16 Python
python 如何引入协程和原理分析
2020/11/30 Python
Python更改pip镜像源的方法示例
2020/12/01 Python
Html5踩坑记之mandMobile使用小记
2020/04/02 HTML / CSS
物流管理毕业生自荐信范文
2014/03/15 职场文书
工作证明范本(2篇)
2014/09/14 职场文书
2019已经过半,你知道年中工作总结该怎么写吗?
2019/07/03 职场文书
关于redisson缓存序列化几枚大坑说明
2021/08/04 Redis
JavaScript的function函数详细介绍
2021/11/20 Javascript
MySQL数据库实验之 触发器和存储过程
2022/06/21 MySQL