当前位置: 首页 > 面试题库 >

使用go处理文件上传

鲁霄
2023-03-14
问题内容

我最近刚开始玩go,所以我还是菜鸟,对不起,如果我犯了太多错误。我已经尝试解决了很长时间,但我只是不明白发生了什么。在我的main.go文件中,我有一个主要功能:

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

问题是,当执行Submit 函数时,它r.MethodGET并且r.Header.Get("Content- Type")是一个空字符串,如果r.FormFile返回以下错误,它将继续执行直到第一个: request Content-Type isn't multipart/form-data 我不明白为什么r.Method总是GET并且没有Content-
类型。我试图以许多不同的方式来做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"
        },
        body: formData
    }).then(function json(response) {
        return response.json()
    }).then(function(data) {
        window.console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
        window.console.log('Request failed', error);
    });
}

这是HTML:

<input id="file-input" type="file" name="uploadFile" />

请注意,标记不在标记内,我认为可能是问题所在,因此我将函数和HTML都更改为如下形式:

function upload() {
    fetch('/submit', {
        method: 'post',
        headers: {
          "Content-Type": "multipart/form-data"
        },
        body: new FormData(document.querySelector('#form')
    }).then(function json(response) {
        return response.json()
    }).then(function(data) {
        window.console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
        window.console.log('Request failed', error);
    });
}

<form id="form" method="post" enctype="multipart/form-data" action="/submit"><input id="file-input" type="file" name="uploadFile" /></form>

但这也不起作用。我在Google上搜索了如何使用fetch()以及如何从go接收文件上传,我发现它们与我的非常相似,我不知道我做错了什么。

更新: 使用后,curl -v -F 'uploadFile=@\"C:/Users/raul-/Desktop/test.png\"' http://localhost:8080/submit我得到以下输出:

* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> POST /submit HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.45.0
> Accept: */*
> Content-Length: 522
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=---------------------------a17d4e54fcec53f8
>
< HTTP/1.1 301 Moved Permanently
< Location: /submit/
< Date: Wed, 18 Nov 2015 14:48:38 GMT
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
* HTTP error before end of send, stop sending
<
* Closing connection 0

go run main.go使用curl时,我运行的控制台没有任何输出。


问题答案:

我设法解决了我的问题,所以这里是万一有人需要的情况。还要感谢@JiangYD提供了使用curl测试服务器的技巧。

  • 我写了,http.HandleFunc("/submit/", submit)但是我正在发出POST请求/submit(请注意缺少斜杠)<<这很重要,因为重定向
  • 不要自己指定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并未提供获取该边界的方法,但我发现浏览器会自动将Content-Type与multipart/form- data和添加边界(如果未指定),因此我从fetch调用中删除了标头对象,现在终于可以了!



 类似资料:
  • 问题内容: 用Flask处理超大文件上传(1 GB以上)的最佳方法是什么? 我的应用程序实际上需要多个文件,为它们分配一个唯一的文件号,然后根据用户选择的位置将其保存在服务器上。 我们如何将文件上传作为后台任务运行,以使用户在1小时内没有浏览器旋转,而是可以立即进入下一页? Flask开发服务器能够处理大量文件(50gb需要1.5个小时,上传速度很快,但将文件写入空白文件的速度却很慢) 如果我用T

  • 你想处理一个由用户上传的文件,比如你正在建设一个类似Instagram的网站,你需要存储用户拍摄的照片。这种需求该如何实现呢? 要使表单能够上传文件,首先第一步就是要添加form的enctype属性,enctype属性有如下三种情况: application/x-www-form-urlencoded 表示在发送前编码所有字符(默认) multipart/form-data 不对字符

  • 用Flask处理非常大的文件上传(1 GB+)的最佳方式是什么? 我的应用程序基本上接受多个文件,为它们分配一个唯一的文件号,然后根据用户选择的位置将其保存在服务器上。 我们如何运行文件上传作为一个后台任务,这样用户就不会有浏览器旋转1小时,而是可以立即进入下一页? null

  • 问题内容: 在Stack Overflow上使用Selenium WebDriver上传文件时,我已经看到很多问题和解决方案。但是它们都不适合以下情况。 有人给出了以下解决方案 但是我仍然找不到窗口句柄。我该如何处理? 我正在寻找上述方案的解决方案。 请在以下任何网站上进行检查。 问题答案: 如果使用Zamzar网站,它应该可以正常运行。你无需单击该元素。你只需在其中输入路径。具体来说,这绝对可以

  • 问题内容: 我想使用PHP上传文件,但问题是我不知道要上传多少文件。 我的问题是,如果使用该如何上传文件? 我将仅添加“文件”框,并使用JavaScript创建更多要上传的文件输入,但是如何在PHP中处理它们呢? 问题答案: 请参阅:$ _FILES ,处理文件上传

  • 问题内容: 我在Java应用程序中使用Hibernate访问我的数据库,它与MS- SQL和MySQL配合得很好。但是我必须以某种形式显示的某些数据必须来自文本文件,对于文本文件,我的意思是人类可读文件,它们可以是CSV,制表符分隔甚至是键,值对,每行,因为我的数据就这么简单,但是我的首选当然是XML文件。 我的问题是:我可以使用Hibernate通过HQL,Query,EntityManager