为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 Go 从一个 HTTP 请求中解析文件和 JSON 数据?

如何使用 Go 从一个 HTTP 请求中解析文件和 JSON 数据?

Go
森林海 2021-09-21 22:45:33
我一直在试图弄清楚如何从 Angularjs 前端的一个 http 请求表单中解析 PDF 文档和 JSON 数据。请求有效载荷是HTTP 请求内容配置:表单数据;名称=“文件”;filename="Parent Handbook.pdf" 内容类型:application/pdf内容配置:表单数据;名称=“文档”{"title":"test","cat":"test cat","date":20142323}“file”是pdf,“doc”是我要解析的json数据。我的处理程序可以很好地解析和保存文件,但无法从 Json 中获取任何内容。有任何想法吗?func (s *Server) PostFileHandler(w http.ResponseWriter, r *http.Request) {    const _24K = (1 << 20) * 24    err := r.ParseMultipartForm(_24K)    if err != nil {        http.Error(w, err.Error(), http.StatusInternalServerError)        return    }    doc := Doc{}    jsonDecoder := json.NewDecoder(r.Body)    fmt.Println(r.Body)    err = jsonDecoder.Decode(&doc)    if err != nil {        fmt.Println(err.Error())    }    fmt.Println(doc.Title, doc.Url, doc.Cat, doc.Date)    doc.Id = len(docs) + 1    err = s.db.Insert(&doc)    checkErr(err, "Insert failed")    // files := m.File["myFile"]    for _, fheaders := range r.MultipartForm.File {        for _, hdr := range fheaders {            var infile multipart.File            infile, err = hdr.Open()            // defer infile.Close()            if err != nil {                http.Error(w, err.Error(), http.StatusInternalServerError)                return            }            doc.Url = hdr.Filename            fmt.Println(hdr.Filename)            var outfile *os.File            outfile, err = os.Create("./docs/" + hdr.Filename)            // defer outfile.Close()            if err != nil {                http.Error(w, err.Error(), http.StatusInternalServerError)                return            }            _, err = io.Copy(outfile, infile)            if err != nil {                http.Error(w, err.Error(), http.StatusInternalServerError)                return            }        }    }    s.Ren.JSON(w, http.StatusOK, &doc)    // http.Error(w, "hit file server", http.StatusOK)}
查看完整描述

1 回答

?
猛跑小猪

TA贡献1858条经验 获得超8个赞

在您的示例中,您试图读取 r.Body 就好像它是从请求的 PDF 部分中剥离出来的一样,但事实并非如此。您需要分别处理 PDF 和 JSON 这两个部分。使用http.(*Request).MultipartReader()。


r.MultipartReader() 将返回mime/multipart.Reader对象,因此您可以使用r.NextPart()函数迭代各个部分并分别处理每个部分。


所以你的处理函数应该是这样的:


func (s *Server) PostFileHandler(w http.ResponseWriter, r *http.Request) {

    mr, err := r.MultipartReader()

    if err != nil {

        http.Error(w, err.Error(), http.StatusInternalServerError)

        return

    }


    doc := Doc{}

    for {

        part, err := mr.NextPart()


        // This is OK, no more parts

        if err == io.EOF {

            break

        }


        // Some error

        if err != nil {

            http.Error(w, err.Error(), http.StatusInternalServerError)

            return

        }


        // PDF 'file' part

        if part.FormName() == "file" {

            doc.Url = part.FileName()

            fmt.Println("URL:", part.FileName())

            outfile, err := os.Create("./docs/" + part.FileName())

            if err != nil {

                http.Error(w, err.Error(), http.StatusInternalServerError)

                return

            }

            defer outfile.Close()


            _, err = io.Copy(outfile, part)

            if err != nil {

                http.Error(w, err.Error(), http.StatusInternalServerError)

                return

            }

        }


        // JSON 'doc' part

        if part.FormName() == "doc" {

            jsonDecoder := json.NewDecoder(part)

            err = jsonDecoder.Decode(&doc)

            if err != nil {

                http.Error(w, err.Error(), http.StatusInternalServerError)

                return

            }

            fmt.Println(doc.Title, doc.Url, doc.Cat, doc.Date)

        }

    }


    doc.Id = len(docs) + 1

    err = s.db.Insert(&doc)

    checkErr(err, "Insert failed")


    s.Ren.JSON(w, http.StatusOK, &doc)

}


查看完整回答
反对 回复 2021-09-21
  • 1 回答
  • 0 关注
  • 353 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信