1. 程式人生 > >解決Go上傳檔案報錯:找不到Boundary的問題

解決Go上傳檔案報錯:找不到Boundary的問題

最近要做一個元件,即接收客戶端的請求,經過一系列的封裝,將請求傳送給真正的服務端器。可以理解為:客戶端使用Http的Request的Body儲存檔案流,將Request傳送給伺服器。遇到一個問題:傳入的是一個檔案控制代碼File,需要轉換成byte[]存到request的body中,但是發現boundary找不到,自行在content-Type中加上Boundary欄位,發現後臺讀取不到檔案流。

1. 首先自己使用Spring Boot搭了一個簡單的server,接收Client傳送過來的request,讀取body然後輸出。啟動的是8080埠,path為/hello,程式碼如下:

2. 客戶端的程式碼:

var file *os.File
file,err = os.Open("src/main/post.txt")
if err != nil {
 fmt.Println(err)
 return
}
defer file.Close()
body := bufio.NewReader(file)
requestWrapper.Request.Body = ioutil.NopCloser(body)

(1).第一步使用os.Open開啟一個檔案,返回的是一個檔案控制代碼os.File型別

(2)然後使用緩衝池的讀取方法NewReader構建一個Reader,此處用的是預設的緩衝池大小:4096,當然可以換做這個方法來主動傳入一個緩衝池大小NewReaderSize(rd, defaultBufSize)

(3)因為Request的Body是一個io.ReadCloser型別,所以需要呼叫ioutil.NopCloser方法將Reader型別轉換成ReadCloser。

3. 萬事俱備,現在執行客戶端程式碼,發現server端報錯:

1533268964_71_w1049_h49.png

即:缺少boundary。

經查閱資料發現,boundary是HttpRequest為multipart型別的contentType設定的一個分隔符,為了使伺服器正確識別檔案的起始位置。瀏覽器會自動生成一個隨機數作為Boundary,也可以自己制定一個固定的boundary,但要足夠複雜,防止與檔案中的內容重複,無法正確識別起始位置。

例如,有Boundary的contentType:"Content-Type", "multipart/form-data; boundary=ABCD"

4. 既然缺少boundary,那麼就為其新增一個Boundary。

requestWrapper.Request.Header.Set("Content-Type", "multipart/form-data;boundary="+ multipart.NewWriter(bytes.NewBufferString("")).Boundary())

此處的Boundary()函式是Writer提供的一個會返回一個隨機數的Boundary

再次啟動,發現server端能夠接收到請求,但是,列印request的body,發現內容為空!!!

百思不得其解。。。。

5. 查閱資料,說刪除自定義的content-Type欄位,嘗試了一下,竟然成功。

Request.Header.Del("Content-Type")

原因是:

原來 post 請求上傳檔案的時候是不需要自己設定 Content-Type,會自動給你新增一個 boundary ,用來分割訊息主體中的每個欄位,如果這個時候自己設定了 Content-Type, 伺服器就不知道怎麼分割各個欄位,因此就會報錯。

如果自己設定了content-Type但是又不設定boundary,自然會出現找不到boundary。

所以!讓瀏覽器自己去設定conten-Type。