golang使用MultipartForm分析http request内容

CodingCode · · 2357 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

golang使用MultipartForm分析http request内容

在使用curl给http server发请求的时候,可以使用-F参数指定这是一个multipart的请求;这种请求可以同时包含文本的form数据,也可以包含二进制文件数据。

下面这段代码是server端分析http请求解析multipart的例子:

func httpHandle(w http.ResponseWriter, r *http.Request) {
    // http.Request has a member MultipartForm, it's defined as:
    // MultipartForm *multipart.Form
    // type Form struct {
    //    Value map[string][]string
    //    File  map[string][]*FileHeader
    // }

    err := r.ParseMultipartForm(1048576)
    if err != nil {
        log.Printf("Cannot ParseMultipartForm, error: %v\n", err)
        return
    }

    if r.MultipartForm == nil {
        log.Printf("MultipartForm is null\n")
        return
    }

    if r.MultipartForm.Value != nil {
        parseMultipartFormValue(r.MultipartForm.Value)
    }

    if r.MultipartForm.File != nil {
        parseMultipartFormFile(r, r.MultipartForm.File)
    }
}

// parse form data
func parseMultipartFormValue(formValues map[string][]string) {
    for formName, values := range formValues {
        log.Printf("Value formname: %s\n", formName)
        for i, value := range values {
            log.Printf("      formdata[%d]: content=[%s]\n", i, value)

            //m := make(map[string]string)
            //_ = json.NewDecoder(strings.NewReader(value)).Decode(&m)
            //log.Printf("      formdata[%d]: json=[%v]\n", i, value)
        }
    }
    return
}

// parse form file
func parseMultipartFormFile(r *http.Request, formFiles map[string][]*multipart.FileHeader) {
    for formName, _ := range formFiles {
        // func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)
        // FormFile returns the first file for the provided form key
        formFile, formFileHeader, _ := r.FormFile(formName)

        log.Printf("File formname: %s, filename: %s, file length: %d\n", formName, formFileHeader.Filename, formFileHeader.Size)

        if strings.HasSuffix(formFileHeader.Filename, ".zip") {
            zipReader, _ := zip.NewReader(formFile, formFileHeader.Size)
            for i, zipMember := range zipReader.File {
                f, _ := zipMember.Open()
                defer f.Close()

                buf, _ := ioutil.ReadAll(f)
                log.Printf("     formfile[%d]: filename=[%s], size=%d, content=[%s]\n", i, zipMember.Name, len(buf), strings.TrimSuffix(string(buf), "\n"))
            }
        } else {
            var b bytes.Buffer
            _, _ = io.Copy(&b, formFile)
            log.Printf("     formfile: content=[%s]\n", strings.TrimSuffix(b.String(), "\n"))
        }
    }
}

客户端调用:

$ curl -X POST -H "Content-Type: multipart/form-data" \
    -F 'payload={"aa":"bb"}' \
    -F 'file1=@a1.txt' \
    -F 'file2=@a3.zip' \
    http://localhost:8080/multipart

举个例子:

2020/04/25 16:24:15 Value formname: payload
2020/04/25 16:24:15       formdata[0]: content=[{"aa":"bb"}]
2020/04/25 16:24:15 File formname: file1, filename: a1.txt, file length: 3
2020/04/25 16:24:15      formfile: content=[a1]
2020/04/25 16:24:15 File formname: file2, filename: a3.zip, file length: 322
2020/04/25 16:24:15      formfile[0]: filename=[a31.txt], size=10, content=[a31a31a31]
2020/04/25 16:24:15      formfile[1]: filename=[a32.txt], size=10, content=[a32a32a32]

这个例子我们看到server端如何解析formdata,如果是json串还可以解析成json对象;以及如何解析上传文件的内容,并且如果是zip文件,还如何读取zip的每一个member。

另外要注意的是,不管是formdata还是formfile,一个form项可对应多个数据;例如:

$ curl -X POST -H "Content-Type: multipart/form-data" \
    -F 'payload={"aa":"bb"}' \
    -F 'payload={"cc":"dd"}' \
    -F 'file1=@a1.txt' \
    -F 'file1=@a3.zip' \
    http://localhost:8080/multipart

这里form payload包含两块内容,form file1也包含两个文件,我不知道为什么要这样设计,为什么要用同一个formname对应多个内容呢,分开不是更好吗?

在实际应用中,我们一般都分开,即不使用一个formname对应多个值,所以request.FormFile()函数只取第一个File对象已经够用了。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:CodingCode

查看原文:golang使用MultipartForm分析http request内容

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2357 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传