解決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端報錯:
即:缺少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。