2015-11-18 19 views
4

我最近开始玩去了,所以我仍然是一个小菜,抱歉,如果我犯了太多的错误。我一直试图解决这个问题很长一段时间,但我只是不明白发生了什么。在我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}) 
} 

的问题是在执行提交功能时,r.MethodGETr.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" 
     }, 
     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上接收文件上传,我已经看到它们与我的非常相似,我不知道我在做什么错误。

UPDATE: 使用curl -v -F '[email protected]\"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 

使用curl时,在那里我遇到go run main.go输出没有控制台。

+1

第一步,使用curl检查服务器是否正常。 –

+0

您需要在窗体标签上设置方法和enctype属性。输入标签与GET/POST决定,多部分编码和内容类型设置无关。 – Volker

+0

@Volker我认为在获取中指定'method:post'和'header:{'Content-Type':'multipart/form-data'}'就足够了,我不需要

标记,但我尝试过使用一个标签,看起来像这样''form id =“form”method =“post”enctype =“multipart/form-data”action =“/ submit”>'然后我使用'新的FormData'提交这种形式的数据,但不起作用,所以我想它一定是别的东西。 – raulsntos

回答

5

我设法解决我的问题,所以在这里它是在别人需要它的情况下。并感谢@JiangYD使用curl来测试服务器的技巧。

TL; DR

  • 我写http.HandleFunc("/submit/", submit),但我是在POST请求/submit(注意没有斜杠)< <这是因为重定向的重要
  • 不指定内容类型自己,浏览器会为你做

长的答案

我一样@Ji angYD说,并用卷曲来测试服务器,我更新了我的回答与答复。我发现奇怪的是,有一个301重定向,因为我没有把它放在那里,我决定用下面的curl命令

curl -v -F '[email protected]\"C:/Users/raul-/Desktop/test.png\"' -L http://localhost:8080/submit 

(注意-L)卷曲这样追踪重定向,但它再次失败的原因是,重定向时,curl从POST切换到GET,但使用该响应,我发现/submit的请求正被重定向到/submit/,我记得那是我在main函数中编写它的方式。

固定,它仍然失败后,反应是http: no such file并通过查看net/http代码,我发现,这意味着该领域是不存在的,所以我做了一个快速测试迭代在获得所有字段名:

​​

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

但它不会在这里结束了,我现在知道服务器是正常工作的文件因为我可以使用curl上传文件,但是当我尝试通过托管网页上传我得到一个错误:no multipart boundary param in Content-Type

所以我发现我是想以包括报头中的边界,我改取到这样的事情:

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和边界,所以我从fetch调用中删除了标题对象,现在它终于起作用了!

+0

感谢您的洞察。帮了我很多。 – darkdefender27