本书未发布

2.8. post提交数据

未匹配的标注

post data

使用Post方法发送一个请求,通过有三种传递数据的方法(不算Header),uri请求参数、url表单、form表单,后两种就是指一般表单请求。

url请求参数

url请求参数是指数据在请的url中的数据.

例如下面这个请求的数据就是a=1&b=2,在请求行中使用url编码。

[root@izj6cffbpd9lzl3tcm2csxz ~]# curl -v -XPOST 'www.example.com?a=1&b=2'
* About to connect() to www.example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to www.example.com (93.184.216.34) port 80 (#0)
> POST /?a=1&b=2 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.example.com
> Accept: */*
> 
< HTTP/1.1 411 Length Required
< Content-Type: text/html
< Content-Length: 357
< Connection: close
< Date: Tue, 16 Jul 2019 09:31:13 GMT
< Server: ECSF (sjc/4E8D)

url表单

url表单指Content-Typeapplication/x-www-form-urlencoded,数据保存在body的表单。

这种就键值对数据,使用url编码,使用curl发送请求,可以看见显示Content-Length的长度是7,Content-Type显示是url编码,这种是url编码表单,数据在在body里面,内容没有显示,但是可以根据数据猜出请求body内容就是a=1&b=2,长度恰好是7。

[root@izj6cffbpd9lzl3tcm2csxz ~]# curl -v -d a=1 -d b=2 www.example.com
* About to connect() to www.example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to www.example.com (93.184.216.34) port 80 (#0)
> POST / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.example.com
> Accept: */*
> Content-Length: 7
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 7 out of 7 bytes
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Tue, 16 Jul 2019 09:25:44 GMT
< Etag: "1541025663"
< Expires: Tue, 23 Jul 2019 09:25:44 GMT
< Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
< Server: EOS (vny006/044F)
< Content-Length: 1270

form表单

form表单指Content-Typemultipart/form-data,数据保存在body的表单。

这个是curl发送一个form表单的内容,可以看到Content-Type的值是multipart/form-data; boundary=----------------------------e55eb170f828,multipart/form-data就表明是一个Form表单,里面boundary的值相当于表单的分隔符用于解析body。

[root@izj6cffbpd9lzl3tcm2csxz ~]# curl -v --form a=1 --form b=2  www.example.com
* About to connect() to www.example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to www.example.com (93.184.216.34) port 80 (#0)
> POST / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.example.com
> Accept: */*
> Content-Length: 228
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=----------------------------e55eb170f828
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Tue, 16 Jul 2019 09:24:46 GMT
< Etag: "1541025663"
< Expires: Tue, 23 Jul 2019 09:24:46 GMT
< Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
< Server: EOS (vny006/044E)
< Content-Length: 1270

golang解析form表单

通常net/http中Request会解析数据。

form表单也可以使用mime/multipart库来解析。

    // 先获取boundary参数
    _, params, err := mime.ParseMediaType(r.Header.Get(HeaderContentType))
    if err != nil {
        return err
    }

    form, err := multipart.NewReader(r, params["boundary"]).ReadForm(32 << 20)
    if err != nil {
        return err
    }
    defer form.RemoveAll()

    form...

form对象就是解析到的数据。

form对象定义在mime/multipart,value就是键值对数据,File是上form中上传的临时文件。

form会把上传的文件存到一个临时目录,最后需要调用RemoveAll删除掉,net/http解除出的Form文件会自动调用删除。

type Form struct {
    Value map[string][]string
    File  map[string][]*FileHeader
}

net/http使用表单

http.Request中Form、PostForm、MultipartForm三个对象和表单数据保存相关。

type Request struct {
    ...
    Form url.Values
    PostForm url.Values // Go 1.1
    MultipartForm *multipart.Form
}

Form保存url请求参数解析出来的数据。

如果是body内容是url表单,解析的数据在PostForm,同时复制一份保存到Form中。

如果是body内容是form表单,解析的数据在MultipartForm,包含Form的Value和File数据,同时复制一份Value保存到Form和PostForm中。

// from godoc
type Request
    func (r *Request) ParseForm() error
    func (r *Request) ParseMultipartForm(maxMemory int64) error
    func (r *Request) FormValue(key string) string
    func (r *Request) PostFormValue(key string) string
    func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)
    func (r *Request) MultipartReader() (*multipart.Reader, error)

Form、PostForm、MultipartForm三个对象默认都是nil,需要调用相关函数后才会触发解析并保存数据,相关一共存在6个方法,触发解析后可以直接使用请求的Form、PostForm、MultipartForm三个对象。如果直接使用Form无法获取到数据,就是没有触发数据解析。

ParseForm方法:如果是请求方法为POST、PUT、PATCH且body内容是url表单会解析body保存到PostForm和Form中,然后再解析url请求参数,该方法无法解析form表单

ParseMultipartForm方法:先调用ParseForm方法一遍,如果不返回err,然后使用body解析成form表单数据保存在MultipartForm中,再复制Form的Value数据到Form和PostForm中,默认最大body是32<<20byte即32MB。

FormValue方法:先调用ParseMultipartForm方法,然后从Form返回数据。

PostFormValue方法:先调用ParseMultipartForm方法,然后从PostForm返回数据,与FormValue方法的区别忽略url请求参数。

FormFile方法:先调用ParseMultipartForm方法,然后从FormFile.File返回文件。

MultipartReader方法:封装请求body成*multipart.Reader,然后可以调用方法解析出Form对象,该行为需要调用Form.RemoveAll方法释放临时文件。

具体实现参考源码

框架

框架可能封装了相关方法,但是均可以获得*http.Request对象,然后标准库相关方法。

反馈和交流请加群组:QQ群373278915

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~