对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 相关文章推荐
Go语言使用select{}阻塞main函数介绍
Apr 25 Golang
Go语言切片前或中间插入项与内置copy()函数详解
Apr 27 Golang
解决go在函数退出后子协程的退出问题
Apr 30 Golang
Golang之sync.Pool使用详解
May 06 Golang
Golang 获取文件md5校验的方法以及效率对比
May 08 Golang
使用GO语言实现Mysql数据库CURD的简单示例
Aug 07 Golang
深入理解go缓存库freecache的使用
Feb 15 Golang
Go语言grpc和protobuf
Apr 13 Golang
golang操作redis的客户端包有多个比如redigo、go-redis
Apr 14 Golang
深入理解 Golang 的字符串
May 04 Golang
Go语言怎么使用变长参数函数
Jul 15 Golang
基于Python实现西西成语接龙小助手
Aug 05 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
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
2009/03/13 PHP
一个PHP的远程图片抓取函数分享
2013/09/25 PHP
php格式化时间戳显示友好的时间实现思路及代码
2014/10/23 PHP
php简单实现多维数组排序的方法
2016/09/30 PHP
Ajax中的JSON格式与php传输过程全面解析
2017/11/14 PHP
浅谈Laravel核心解读之Console内核
2018/12/02 PHP
PHP实现读取文件夹及批量重命名文件操作示例
2019/04/15 PHP
thinkphp 框架数据库切换实现方法分析
2020/05/18 PHP
JavaScript面向对象之体会[总结]
2008/11/13 Javascript
jquery对表单操作2
2011/04/06 Javascript
JavaScript实现的石头剪刀布游戏源码分享
2014/08/22 Javascript
jquery 获取 outerHtml 包含当前节点本身的代码
2014/10/30 Javascript
微信JSSDK上传图片
2015/08/23 Javascript
js仿支付宝填写支付密码效果实现多方框输入密码
2016/03/09 Javascript
js实现音频控制进度条功能
2017/04/01 Javascript
2种简单的js倒计时方式
2017/10/20 Javascript
vue-cli + sass 的正确打开方式图文详解
2017/10/27 Javascript
基于vue-resource jsonp跨域问题的解决方法
2018/02/03 Javascript
vue项目前端微信JSAPI与外部H5支付相关实现过程及常见问题
2020/04/14 Javascript
[45:44]完美世界DOTA2联赛PWL S2 FTD vs PXG 第一场 11.27
2020/12/01 DOTA
Django中URL视图函数的一些高级概念介绍
2015/07/20 Python
python使用matplotlib绘制柱状图教程
2017/02/08 Python
在Python web中实现验证码图片代码分享
2017/11/09 Python
Django 2.0版本的新特性抢先看!
2018/01/05 Python
python使用PIL给图片添加文字生成海报示例
2018/08/17 Python
python3实现指定目录下文件sha256及文件大小统计
2019/02/25 Python
pytorch中torch.max和Tensor.view函数用法详解
2020/01/03 Python
opencv 形态学变换(开运算,闭运算,梯度运算)
2020/07/07 Python
Python程序慢的重要原因
2020/09/04 Python
快速解决pymongo操作mongodb的时区问题
2020/12/05 Python
俄罗斯便宜的在线服装商店:GroupPrice
2020/04/10 全球购物
怎样声明一个匿名的内部类
2016/06/01 面试题
舞蹈专业大学生职业规划范文
2014/03/12 职场文书
退伍军人感言
2015/08/01 职场文书
Golang 编译成DLL文件的操作
2021/05/06 Golang
PostgreSQL数据库去除重复数据和运算符的基本查询操作
2022/04/12 PostgreSQL