2015-11-18 57 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