对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中semaphore(信号量)源码
Apr 03 Golang
golang import自定义包方式
Apr 29 Golang
golang 比较浮点数的大小方式
May 02 Golang
手把手教你导入Go语言第三方库
Aug 04 Golang
深入理解go slice结构
Sep 15 Golang
Go 语言中 20 个占位符的整理
Oct 16 Golang
Golang使用Panic与Recover进行错误捕获
Mar 22 Golang
简单聊聊Golang中defer预计算参数
Mar 25 Golang
Golang 切片(Slice)实现增删改查
Apr 22 Golang
Go web入门Go pongo2模板引擎
May 20 Golang
Go 内联优化让程序员爱不释手
Jun 21 Golang
Go微服务项目配置文件的定义和读取示例详解
Jun 21 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
PHP Mysql编程之高级技巧
2008/08/27 PHP
比较全面的PHP数组的使用方法小结
2010/09/23 PHP
php学习之数据类型之间的转换介绍
2011/06/09 PHP
PHP命名空间(Namespace)简明教程
2014/06/11 PHP
yii框架结合charjs实现统计30天数据的方法
2020/04/04 PHP
利用js对象弹出一个层
2008/03/26 Javascript
不用AJAX和IFRAME,说说真正意义上的ASP+JS无刷新技术
2008/09/25 Javascript
JQuery Ajax 跨域访问的解决方案
2010/03/12 Javascript
基于Jquery的动态创建DOM元素的代码
2010/12/28 Javascript
与jquery serializeArray()一起使用的函数,主要来方便提交表单
2011/01/31 Javascript
使用jQuery动态加载js脚本文件的方法
2014/04/03 Javascript
AngularJs实现ng1.3+表单验证
2015/12/10 Javascript
深入理解MVC中的时间js格式化
2016/05/19 Javascript
nodejs和php实现图片访问实时处理
2017/01/05 NodeJs
Vue.js实现移动端短信验证码功能
2017/03/29 Javascript
jsonp实现百度下拉框功能的方法分析
2019/05/10 Javascript
使用vscode快速建立vue模板过程详解
2019/10/10 Javascript
vue+axios 拦截器实现统一token的案例
2020/09/11 Javascript
Vue实现简单计算器
2021/01/20 Vue.js
Python2.7简单连接与操作MySQL的方法
2016/04/27 Python
Python简单读取json文件功能示例
2017/11/30 Python
分分钟入门python语言
2018/03/20 Python
在pycharm下设置自己的个性模版方法
2019/07/15 Python
Python queue队列原理与应用案例分析
2019/09/27 Python
你应该知道的Python3.6、3.7、3.8新特性小结
2020/05/12 Python
Python新手学习raise用法
2020/06/03 Python
凯撒娱乐:Caesars Entertainment
2018/02/23 全球购物
哈曼俄罗斯官方网上商店:Harman.club
2020/07/24 全球购物
武汉瑞得软件笔试题
2015/10/27 面试题
高级电工工作职责
2013/11/21 职场文书
实习介绍信模板
2015/01/30 职场文书
写给汽车4S店的创业计划书,拿来即用!
2019/08/09 职场文书
html+css 实现简易导航栏功能
2021/04/07 HTML / CSS
django学习之ajax post传参的2种格式实例
2021/05/14 Python
深入浅析Redis 集群伸缩原理
2021/05/15 Redis
zabbix监控mysql的实例方法
2021/06/02 MySQL