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

使用 go 处理文件上传

使用 go 处理文件上传

Go
慕勒3428872 2021-11-22 17:47:45
我最近开始玩围棋,所以我还是个菜鸟,如果我犯了太多错误,请见谅。我一直试图解决这个问题很长时间,但我只是不明白发生了什么。在我的 main.go 文件中,我有一个 main 函数:func main() {    http.HandleFunc("/", handler)    http.HandleFunc("/submit/", submit)    log.Fatal(http.ListenAndServe(":8080", nil))}处理程序函数如下所示:func handler(w http.ResponseWriter, r *http.Request) {    data, _ := ioutil.ReadFile("web/index.html")    w.Write(data)}我知道这不是为网站提供服务的最佳方式提交功能如下所示:func submit(w http.ResponseWriter, r *http.Request) {    log.Println("METHOD IS " + r.Method + " AND CONTENT-TYPE IS " + r.Header.Get("Content-Type"))    r.ParseMultipartForm(32 << 20)    file, header, err := r.FormFile("uploadFile")    if err != nil {        json.NewEncoder(w).Encode(Response{err.Error(), true})        return    }    defer file.Close()    out, err := os.Create("/tmp/file_" + time.Now().String() + ".png")    if err != nil {        json.NewEncoder(w).Encode(Response{err.Error(), true})        return    }    defer out.Close()    _, err = io.Copy(out, file)    if err != nil {        json.NewEncoder(w).Encode(Response{err.Error(), true})        return    }    json.NewEncoder(w).Encode(Response{"File '" + header.Filename + "' submited successfully", false})}问题是,当执行功能的提交,r.Method是GET和r.Header.Get("Content-Type")是一个空字符串,然后继续,直到第一,如果其中r.FormFile返回以下错误: request Content-Type isn't multipart/form-data 我不明白为什么r.Method总是GET和没有内容-类型。我尝试以多种不同的方式执行 index.html,但 r.Method 始终为 GET,而 Content-Type 为空。这是 index.html 中上传文件的函数:function upload() {    var formData = new FormData();    formData.append('uploadFile', document.querySelector('#file-input').files[0]);    fetch('/submit', {        method: 'post',        headers: {          "Content-Type": "multipart/form-data"        },但这也不起作用。我用 Google 搜索过如何使用 fetch() 以及如何从 go 接收文件上传,我发现它们与我的非常相似,我不知道我做错了什么。
查看完整描述

2 回答

?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

我设法解决了我的问题,所以在这里以防其他人需要它。并感谢@JiangYD 提供使用 curl 测试服务器的技巧。


TL; 博士

我写了,http.HandleFunc("/submit/", submit)但我正在向/submit(注意缺少的斜线)发出 POST 请求<<这很重要,因为重定向

不要自己指定 Content-Type,浏览器会为你做

长答案

我按照@JiangYD 说的做了,并使用curl 来测试服务器,我用响应更新了我的答案。我发现奇怪的是有一个 301 重定向,因为我没有把它放在那里,我决定使用以下 curl 命令


curl -v -F 'uploadFile=@\"C:/Users/raul-/Desktop/test.png\"' -L http://localhost:8080/submit

(注意-L)那样 curl 跟随重定向,尽管它再次失败,因为在重定向时,curl 从 POST 切换到 GET 但通过该响应我发现请求/submit被重定向到/submit/,我记得我是这样写的它在main函数中。


在修复它仍然失败后,响应是http: no such file并且通过查看net/http代码我发现这意味着该字段不存在,因此我对获得的所有字段名称进行了快速迭代:


for k, _ := range r.MultipartForm.File {

    log.Println(k)

}

我得到'uploadFile了字段名称,我删除了 curl 命令中的单引号,现在它完美地上传了文件


但这并没有结束,我现在知道服务器工作正常,因为我可以使用上传文件,curl但是当我尝试通过托管网页上传文件时,出现错误:no multipart boundary param in Content-Type.


所以我发现我应该在标题中包含边界,我将 fetch 更改为这样的:


fetch('/submit', {

    method: 'post',

    headers: {

        "Content-Type": "multipart/form-data; boundary=------------------------" + boundary

    }, body: formData})

我像这样计算边界:


var boundary = Math.random().toString().substr(2);

但是我还是有一个错误:multipart: NextPart: EOF那么你如何计算边界?我阅读了规范https://html.spec.whatwg.org/multipage/forms.html#multipart/form-data-encoding-algorithm并发现边界是由对文件进行编码的算法计算的,在我的情况下是 FormData,FormData API 没有公开获取该边界的方法,但我发现浏览器会multipart/form-data自动添加 Content-Type with和边界,如果您不指定它,所以我从fetch调用中删除了 headers 对象和现在它终于起作用了!


查看完整回答
反对 回复 2021-11-22
?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

完全删除标题实际上有效。尤其是通过 fetch 或 axios 发送请求时。


axios.post(

                    endpoint + "/api/v1/personalslip",

                    {

                      newSlip

                    },

                    {



                     

                    }

                  )

                  .then(res => {

                    console.log(res);

                  });


查看完整回答
反对 回复 2021-11-22
  • 2 回答
  • 0 关注
  • 181 浏览
慕课专栏
更多

添加回答

举报

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