对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原生库的中bytes.Buffer用法
Apr 25 Golang
golang中切片copy复制和等号复制的区别介绍
Apr 27 Golang
go goroutine 怎样进行错误处理
Jul 16 Golang
基于Go语言构建RESTful API服务
Jul 25 Golang
深入理解go slice结构
Sep 15 Golang
Golang MatrixOne使用介绍和汇编语法
Apr 19 Golang
Golang解析JSON对象
Apr 30 Golang
Golang 入门 之url 包
May 04 Golang
详解Go语言中Get/Post请求测试
Jun 01 Golang
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 Golang
Golang gRPC HTTP协议转换示例
Jun 16 Golang
Go中使用gjson来操作JSON数据的实现
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
地球防卫队:陪着奥特曼打小怪兽的人类力量 那些经典队服
2020/03/08 日漫
PHP根据IP地址获取所在城市具体实现
2013/11/27 PHP
ThinkPHP模板判断输出Present标签用法详解
2014/06/30 PHP
windows下安装php的memcache模块的方法
2015/04/07 PHP
PHP合并数组+号和array_merge的区别
2015/06/25 PHP
Yii使用DeleteAll连表删除出现报错问题的解决方法
2016/07/14 PHP
Yii 2中的load()和save()示例详解
2017/08/03 PHP
ThinkPHP框架下微信支付功能总结踩坑笔记
2019/04/10 PHP
Yii2.0框架模型多表关联查询示例
2019/07/18 PHP
JS效率个人经验谈(8-15更新),加入range技巧
2007/01/09 Javascript
初窥JQuery(二) 事件机制(1)
2010/11/25 Javascript
使用Jquery搭建最佳用户体验的登录页面之记住密码自动登录功能(含后台代码)
2011/07/10 Javascript
js实现的黑背景灰色二级导航菜单效果代码
2015/08/24 Javascript
JS闭包、作用域链、垃圾回收、内存泄露相关知识小结
2016/05/16 Javascript
12个非常实用的JavaScript小技巧【推荐】
2016/05/18 Javascript
使用JavaScript判断用户输入的是否为正整数(两种方法)
2017/02/05 Javascript
Vue 进阶教程之v-model详解
2017/05/06 Javascript
react 应用多入口配置及实践总结
2018/10/17 Javascript
vue+webpack dev本地调试全局样式引用失效的解决方案
2019/11/12 Javascript
JavaScript交换两个变量方法实例
2019/11/25 Javascript
three.js利用射线Raycaster进行碰撞检测
2020/03/12 Javascript
部署vue+Springboot前后端分离项目的步骤实现
2020/05/31 Javascript
JavaScript实现简单验证码
2020/08/24 Javascript
python实现读取excel写入mysql的小工具详解
2017/11/20 Python
详解Python 字符串相似性的几种度量方法
2019/08/29 Python
TENSORFLOW变量作用域(VARIABLE SCOPE)
2020/01/10 Python
python如何设置静态变量
2020/09/07 Python
html5的websockets全双工通信详解学习示例
2014/02/26 HTML / CSS
韩国三大免税店之一:THE GRAND 中文免税店
2016/07/21 全球购物
斯图尔特·韦茨曼鞋加拿大官网:Stuart Weitzman加拿大
2019/10/13 全球购物
EJB3.1都有哪些改进
2012/11/17 面试题
高校毕业生自我鉴定
2013/10/27 职场文书
怎样填写就业意向
2014/04/02 职场文书
大学生新学期计划书
2014/04/28 职场文书
计划生育个人总结
2015/03/02 职场文书
观看《筑梦中国》纪录片心得体会
2016/01/18 职场文书