对Golang中的FORM相关字段理解

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)
}

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

(0)

相关推荐

  • 解决golang post文件时Content-Type出现的问题

    同事用php写了一个接口,要上传文件,让我做下测试,直接用curl命令调用成功,然后想用golang写个示例, 源码如下: package main import ( "bytes" "fmt" "io/ioutil" "mime/multipart" "net/http" ) func main() { uri := "http://xxxxxxxxxxxx/api/fileattr"

  • go浮点数转字符串保留小数点后N位的完美解决方法

    最近在项目中碰到很多次float转string,同时要求保留小数点后几位,并且去掉小数点后0的场景 虽然问题很简单,但是隔了挺久没处理这种场景就有些生疏了,自己也搜了一下,很多回答都不太满意.这里贴一下自己的做法,如果有更好的解决办法的话,还请多多指教 // 主要逻辑就是先乘,trunc之后再除回去,就达到了保留N位小数的效果 func FormatFloat(num float64, decimal int) string { // 默认乘1 d := float64(1) if decima

  • 解决Golang中goroutine执行速度的问题

    突然想到了之前一直没留意的for循环中开goroutine的执行顺序问题,就找了段代码试了试,试了几次后发现几个有意思的地方,我暂时没有精力往更深处挖掘,希望有golang大神能简单说一说这几个地方是怎么回事. 代码: package main import "fmt" func Count(ch chan int) { fmt.Println("Count doing") ch <- 1 fmt.Println("Counting") }

  • golang中json小谈之字符串转浮点数的操作

    有时会有这种需求,将一个json数据形如: {"x":"golang", "y":"520.1314"} 中的y反序列化为浮点类型,如果这样写: package main import ( "encoding/json" "fmt" ) type JsonTest struct { X string `json:"x"` Y float64 `json:"y

  • golang 比较浮点数的大小方式

    Golang浮点数比较和运算会出现误差. 浮点数储存至内存中时,2的-1.-2---n次方不能精确的表示小数部分,所以再把这个数从地址中取出来进行计算就出现了偏差. package main import ( "errors" "fmt" "github.com/shopspring/decimal" ) func FloatCompare(f1, f2 interface{}) (n int, err error) { var f1Dec, f

  • 解决golang结构体tag编译错误的问题

    写了一个带标签的结构体 type server struct{ XMLName xml.Name 'xml:"server"' } 解决 编译错误field tag must be a string,后来发现是后面标签上引号不正确,不应该是回车键旁边的单引号,而是数字键1旁边的单引号 type server struct{ XMLName xml.Name `xml:"server"` } 补充:golang中struct成员变量的标签(Tag)说明和获取方式 在处

  • golang 打印error的堆栈信息操作

    众所周知,目前的golang error只关注Error()信息,而不关注它的堆栈路径,对错误的定位大多数通过 log.SetFlags(log.Llongfile| log.LstdFlags) log.Println(e) 一旦代码分层,为了定位错误,可能出现每一个层次的同一个error,都得log好几次,比如: func DB()error{ return errors.New("time out") } func Dao()error{ if er:= DB();er!=nil

  • golang 实现Location跳转方式

    golang作为互联网时代的C语言,对网络的支持是非常友好的,最近想做个短网址转发使用,自然想到用Golang开发. 闲话少说,直接上源码: package main import ( "fmt" "log" "net/http" ) func login(w http.ResponseWriter, r *http.Request) { fmt.Print(fmt.Sprintf("%v+", r)) w.Header().

  • 对Golang中的FORM相关字段理解

    Form 字段 通过调用Request结构体提供的方法,我们可以将URL.Body.或者以上两者的数据提取到该结构体的Form.PostForm和MultipartForm等字段中. (1)调用ParseForm方法或者ParseMultipartForm方法,对请求进行分析 (2)访问相应的字段 事例: package main import ( "net/http" "fmt" ) func process(w http.ResponseWriter, r *h

  • Golang中time.After的使用理解与释放问题

    Golang中的time.After的使用理解 关于在goroutine中使用time.After的理解, 新手在学习过程中的"此时此刻"的理解,错误还请指正. 先线上代码: package main import ( "fmt" "time" ) func main() { //closeChannel() c := make(chan int) timeout := time.After(time.Second * 2) // t1 := t

  • golang中bufio.SplitFunc的深入理解

    前言 bufio模块是golang标准库中的模块之一,主要是实现了一个读写的缓存,用于对数据的读取或者写入操作.该模块在多个涉及io的标准库中被使用,比如http模块中使用buffio来完成网络数据的读写,压缩文件的zip模块利用bufio来操作文件数据的读写等. golang的bufio包里面定以的SplitFunc是一个比较重要也比较难以理解的东西,本文希望通过结合简单的实例介绍SplitFunc的工作原理以及如何实现一个自己的SplitFunc. 一个例子 在bufio包里面定义了一些常用

  • 初步解读Golang中的接口相关编写方法

    概述 如果说goroutine和channel是Go并发的两大基石,那么接口是Go语言编程中数据类型的关键.在Go语言的实际编程中,几乎所有的数据结构都围绕接口展开,接口是Go语言中所有数据结构的核心. Go语言中的接口是一些方法的集合(method set),它指定了对象的行为:如果它(任何数据类型)可以做这些事情,那么它就可以在这里使用. 接口的定义和使用 比如 复制代码 代码如下: type I interface{     Get() int     Put(int)   } 这段话就定

  • golang中按照结构体的某个字段排序实例代码

    目录 概述 从大到小排序 按照结构体的某个字段排序 使用 sort.Stable 进行稳定排序 附:根据结构体中任意字段进行排序 总结 概述 golang的sort包默认支持int, float64, string的从小大到排序: int -> Ints(x []int)float64 -> Float64s(x []float64)string -> Strings(x []string) 同时它还提供了自定义的排序接口Interface,此接口保护三个方法. type Interfa

  • golang中的defer函数理解

    目录 golang的defer 什么是defer 理解defer defer什么时间执行(defer. return.返回值 三者的执行顺序) defer输出的值,就是定义时的值.而不是defer真正执行时的变量值(注意引用情况) 多个defer,执行顺序 defer的函数一定会执行么? panic情况 os.Exit情况 kill情况(Ctrl+C) 参考文献 golang的defer 什么是defer defer的的官方文档:https://golang.org/ref/spec#Defer

  • golang中使用proto3协议导致的空值字段不显示的问题处理方案

    最近在使用grpc协议的时候,由于采用的是Proto3协议,在查找记录信息的时候,由于某些字段会有默认空值,导致在通过协议调用后,返回的json结构中并没有这些字段,虽然作为前端使用没有太大的问题,但是在更多的使用场景中,我们更需要知道该服务返回的确切字段,以便于能够做相应处理,尤其是编译型语言 具体的使用出现场景如下 type MemberResponse struct { Id int32 `json "id"` Phone string `json "phone&quo

  • Golang中Gin框架的使用入门教程

    目录 安装与简单测试 常见请求与分组请求 获取参数 与 参数合法性验证 获得query中参数 获得multipart/urlencoded form中的参数 模型绑定和参数验证 自定义参数验证 项目结构参考 Gin框架运行模式 Gin如何获取客户ip Gin处理请求结果 以String类型响应请求 以Json格式响应请求 以文件形式响应请求 设置http响应头 Gin处理html模板 Gin访问静态资源文件 Gin处理Cookie操作 Gin文件上传 Gin中间件 官方地址:gin-gonic.

  • Golang中的参数传递示例详解

    前言 本文主要给大家介绍了关于Golang参数传递的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 关于参数传递,Golang文档中有这么一句: after they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. 函数调用参数均为值传递,不是指针传递或引用传递.经测试引申出来,

  • golang中struct和interface的基础使用教程

    前言 本文主要给大家介绍了关于golang中struct和interface的相关内容,是属于golang的基本知识,下面话不多说了,来一起看看详细的介绍吧. struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套:go中的struct类型理解为类,可以定义方法,和函数定义有些许区别:struct类型是值类型. struct定义 type User struct { Name string Age int32 mess string } var user User

随机推荐